mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3429 lines
83 KiB
3429 lines
83 KiB
/*++
|
|
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
srvhandl.c
|
|
|
|
Abstract:
|
|
|
|
This module implements all file descriptor oriented APIs.
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 30-Mar-1989
|
|
Ellen Aycock-Wright (ellena) Nov-1990
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include <sys/stat.h>
|
|
#include "psxsrv.h"
|
|
|
|
#define NTPSX_ONLY
|
|
#include "sesport.h"
|
|
|
|
void
|
|
FindOwnerModeFile(
|
|
IN HANDLE FileHandle,
|
|
OUT struct stat *StatBuf
|
|
);
|
|
|
|
PSID
|
|
GetLoginGroupSid(
|
|
IN PPSX_PROCESS p
|
|
);
|
|
|
|
static PVOID pvInitSDMem[10];
|
|
|
|
ULONG OflagToDesiredAccess[8] = {
|
|
FILE_READ_DATA,
|
|
FILE_WRITE_DATA,
|
|
FILE_READ_DATA | FILE_WRITE_DATA,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
};
|
|
|
|
PSID MakeSid();
|
|
static BOOLEAN IsUserInGroup(
|
|
PPSX_PROCESS p,
|
|
PSID Group
|
|
);
|
|
|
|
BOOLEAN Open(
|
|
PPSX_PROCESS p,
|
|
PPSX_API_MSG m,
|
|
PUNICODE_STRING Path,
|
|
ULONG,
|
|
mode_t,
|
|
PULONG pRetVal,
|
|
PULONG Error
|
|
);
|
|
|
|
|
|
BOOLEAN
|
|
PsxOpen(
|
|
IN PPSX_PROCESS p,
|
|
IN OUT PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX Open.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the open request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_OPEN_MSG args;
|
|
NTSTATUS Status;
|
|
BOOLEAN r;
|
|
|
|
args = &m->u.Open;
|
|
|
|
//
|
|
// Check validity of pathname pointer
|
|
//
|
|
|
|
if (!ISPOINTERVALID_CLIENT(p, args->Path_U.Buffer,
|
|
args->Path_U.Length)) {
|
|
|
|
KdPrint(("Invalid pointer to open: 0x%x\n",
|
|
args->Path_U.Buffer));
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
r = Open(p, m, &args->Path_U, args->Flags, args->Mode, &m->ReturnValue,
|
|
&m->Error);
|
|
|
|
EndImpersonation();
|
|
|
|
return r;
|
|
}
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
|
|
BOOLEAN
|
|
Open(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m,
|
|
IN PUNICODE_STRING Path,
|
|
IN ULONG Flags,
|
|
IN mode_t Mode,
|
|
OUT PULONG pRetVal,
|
|
OUT PULONG pError
|
|
)
|
|
{
|
|
HANDLE FileHandle;
|
|
NTSTATUS Status;
|
|
PFILEDESCRIPTOR Fd;
|
|
ULONG FdIndex;
|
|
ULONG DesiredAccess;
|
|
IO_STATUS_BLOCK Iosb;
|
|
ULONG Options;
|
|
FILE_INTERNAL_INFORMATION SerialNumber;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
ULONG FileClass;
|
|
FILE_ALLOCATION_INFORMATION AllocationInfo;
|
|
FILE_BASIC_INFORMATION BasicInfo;
|
|
struct stat StatBuf;
|
|
ULONG PosixTime;
|
|
ULONG len;
|
|
|
|
Fd = AllocateFd(p, 0, &FdIndex);
|
|
if (NULL == Fd) {
|
|
// No file descriptors are available.
|
|
|
|
*pError = EMFILE;
|
|
return TRUE;
|
|
}
|
|
|
|
DesiredAccess = OflagToDesiredAccess[Flags & O_ACCMODE];
|
|
|
|
//
|
|
// Whenever a file is opened, its ownership, protection, file type
|
|
// information is available. This implies that to view a file from
|
|
// posix, the following access rights are required:
|
|
//
|
|
// READ_CONTROL - to derive owner and mode
|
|
// FILE_READ_ATTRIBUTES - to read control bit to see if what we
|
|
// got was a pipe
|
|
// FILE_READ_EA - to read EA's that determine object type
|
|
// SYNCHRONIZE - to do syncronous IO
|
|
//
|
|
|
|
DesiredAccess |= (SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES |
|
|
FILE_READ_EA);
|
|
|
|
Options = FILE_SYNCHRONOUS_IO_NONALERT;
|
|
|
|
//
|
|
// If the pathname is /dev/tty, make the fd be open
|
|
// on the process console.
|
|
//
|
|
|
|
{
|
|
UNICODE_STRING U;
|
|
|
|
PSX_GET_STRLEN(DOSDEVICE_X2_A,len);
|
|
|
|
PSX_GET_SESSION_OBJECT_NAME(&U, DEV_TTY);
|
|
|
|
if (Path->Length == U.Length &&
|
|
0 == wcsncmp(&Path->Buffer[len], &U.Buffer[len], 8)) {
|
|
|
|
*pRetVal = FdIndex;
|
|
*pError = OpenTty(p, Fd, DesiredAccess, Flags, TRUE);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the pathname is /dev/null, make the fd be open
|
|
// on the corresponding special device.
|
|
//
|
|
|
|
{
|
|
UNICODE_STRING U;
|
|
|
|
PSX_GET_STRLEN(DOSDEVICE_X2_A,len);
|
|
|
|
PSX_GET_SESSION_OBJECT_NAME(&U, DEV_NULL);
|
|
|
|
if (Path->Length == U.Length &&
|
|
0 == wcsncmp(&Path->Buffer[len], &U.Buffer[len], 8)) {
|
|
|
|
*pRetVal = FdIndex;
|
|
*pError = OpenDevNull(p, Fd, DesiredAccess, Flags);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We ask for delete access when we open the file, and if we
|
|
// can't get it we try without. If the file is unlinked while
|
|
// it's open, it gets moved to the junkyard, and when the last
|
|
// close occurs we use the delete access to remove it.
|
|
//
|
|
|
|
DesiredAccess |= DELETE;
|
|
|
|
if (Flags & O_CREAT) {
|
|
CHAR buf[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|
PSECURITY_DESCRIPTOR pSD = (PVOID)buf;
|
|
|
|
Status = InitSecurityDescriptor(pSD, Path, p->Process,
|
|
(Mode & _S_PROT) & ~p->FileModeCreationMask,
|
|
pvInitSDMem);
|
|
if (!NT_SUCCESS(Status)) {
|
|
*pError = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
InitializeObjectAttributes(&ObjA, Path, 0, NULL, pSD);
|
|
|
|
Status = NtCreateFile(&FileHandle, DesiredAccess, &ObjA, &Iosb,
|
|
NULL, FILE_ATTRIBUTE_NORMAL, SHARE_ALL,
|
|
(Flags & O_EXCL) ? FILE_CREATE : FILE_OPEN_IF,
|
|
Options, NULL, 0);
|
|
|
|
if (STATUS_ACCESS_DENIED == Status ||
|
|
STATUS_SHARING_VIOLATION == Status) {
|
|
DesiredAccess &= ~DELETE;
|
|
|
|
Status = NtCreateFile(&FileHandle, DesiredAccess,
|
|
&ObjA, &Iosb,
|
|
NULL, FILE_ATTRIBUTE_NORMAL, SHARE_ALL,
|
|
(Flags & O_EXCL) ? FILE_CREATE : FILE_OPEN_IF,
|
|
Options, NULL, 0);
|
|
}
|
|
|
|
DeInitSecurityDescriptor(pSD, pvInitSDMem);
|
|
|
|
} else {
|
|
InitializeObjectAttributes(&ObjA, Path, 0, NULL, NULL);
|
|
|
|
Status = NtOpenFile(&FileHandle, DesiredAccess, &ObjA, &Iosb,
|
|
SHARE_ALL, Options);
|
|
|
|
if (STATUS_ACCESS_DENIED == Status ||
|
|
STATUS_SHARING_VIOLATION == Status) {
|
|
DesiredAccess &= ~DELETE;
|
|
|
|
Status = NtOpenFile(&FileHandle, DesiredAccess, &ObjA, &Iosb,
|
|
SHARE_ALL, Options);
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (Status == STATUS_OBJECT_PATH_NOT_FOUND) {
|
|
*pError = PsxStatusToErrnoPath(Path);
|
|
return TRUE;
|
|
}
|
|
*pError = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Determine what type of file we have here.
|
|
//
|
|
|
|
FileClass = PsxDetermineFileClass(FileHandle);
|
|
|
|
if (S_IFDIR == FileClass &&
|
|
(DesiredAccess & FILE_WRITE_DATA)) {
|
|
//
|
|
// 1003.1-90 (5.3.1.4): the open() function shall return
|
|
// -1 and set errno...
|
|
// [EISDIR] The named file is a directory, and
|
|
// the oflag argument specifies write
|
|
// or read/write access.
|
|
NtClose(FileHandle);
|
|
*pError = EISDIR;
|
|
return TRUE;
|
|
}
|
|
|
|
if ((Flags & O_TRUNC) && FileClass != S_IFIFO &&
|
|
(DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA))) {
|
|
|
|
AllocationInfo.AllocationSize = RtlConvertLongToLargeInteger(0);
|
|
Status = NtSetInformationFile(FileHandle, &Iosb,
|
|
&AllocationInfo, sizeof(AllocationInfo), FileAllocationInformation);
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(FileHandle);
|
|
*pError = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
Fd->SystemOpenFileDesc = AllocateSystemOpenFile();
|
|
if (! Fd->SystemOpenFileDesc) {
|
|
NtClose(FileHandle);
|
|
*pError = ENOMEM;
|
|
return TRUE;
|
|
}
|
|
|
|
Fd->SystemOpenFileDesc->NtIoHandle = FileHandle;
|
|
|
|
if (DesiredAccess & FILE_READ_DATA) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_READ;
|
|
}
|
|
if (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_WRITE;
|
|
}
|
|
if (Flags & O_NONBLOCK) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_NOBLOCK;
|
|
}
|
|
if (Flags & O_APPEND) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_APPEND;
|
|
}
|
|
|
|
//
|
|
// Get serial numbers.
|
|
//
|
|
|
|
Status = NtQueryInformationFile(FileHandle, &Iosb, &SerialNumber,
|
|
sizeof(SerialNumber), FileInternalInformation);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(FileHandle);
|
|
*pError = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
if (ReferenceOrCreateIoNode(GetFileDeviceNumber(Path),
|
|
(ino_t)SerialNumber.IndexNumber.LowPart,
|
|
FALSE, &Fd->SystemOpenFileDesc->IoNode)) {
|
|
|
|
//
|
|
// Existing Node Minimal Init
|
|
//
|
|
|
|
RtlLeaveCriticalSection(
|
|
&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
|
*pRetVal = FdIndex;
|
|
return IoOpenNewHandle(p, Fd, m);
|
|
}
|
|
|
|
if (! Fd->SystemOpenFileDesc->IoNode) {
|
|
NtClose(FileHandle);
|
|
*pError = ENOMEM;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// New IoNode; lots of initialization
|
|
//
|
|
|
|
if (FileClass == S_IFIFO) {
|
|
Fd->SystemOpenFileDesc->IoNode->IoVectors = &NamedPipeVectors;
|
|
Fd->SystemOpenFileDesc->IoNode->Context =
|
|
RtlAllocateHeap(PsxHeap, 0, sizeof(LOCAL_PIPE));
|
|
InitializeLocalPipe(
|
|
(PLOCAL_PIPE)Fd->SystemOpenFileDesc->IoNode->Context);
|
|
} else {
|
|
Fd->SystemOpenFileDesc->IoNode->IoVectors = &FileVectors;
|
|
}
|
|
|
|
PSX_GET_STRLEN("/DosDevices/X:",len);
|
|
Fd->SystemOpenFileDesc->IoNode->PathLength = Path->Length/2 - len;
|
|
|
|
StatBuf.st_mode = FileClass;
|
|
FindOwnerModeFile(FileHandle, &StatBuf);
|
|
Fd->SystemOpenFileDesc->IoNode->Mode =
|
|
StatBuf.st_mode & ~(p->FileModeCreationMask);
|
|
|
|
Fd->SystemOpenFileDesc->IoNode->OwnerId = StatBuf.st_uid;
|
|
Fd->SystemOpenFileDesc->IoNode->GroupId = StatBuf.st_gid;
|
|
|
|
//
|
|
// Get the file timestamps, convert to Posix format, and stash
|
|
// them away in the IoNode.
|
|
//
|
|
|
|
Status = NtQueryInformationFile(FileHandle, &Iosb, (PVOID)&BasicInfo,
|
|
sizeof(BasicInfo), FileBasicInformation);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
*pError = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
if (!RtlTimeToSecondsSince1970(&BasicInfo.LastAccessTime, &PosixTime)) {
|
|
PosixTime = 0;
|
|
}
|
|
Fd->SystemOpenFileDesc->IoNode->AccessDataTime = PosixTime;
|
|
|
|
if (!RtlTimeToSecondsSince1970(&BasicInfo.LastWriteTime, &PosixTime)) {
|
|
PosixTime = 0;
|
|
}
|
|
Fd->SystemOpenFileDesc->IoNode->ModifyDataTime = PosixTime;
|
|
|
|
if (!RtlTimeToSecondsSince1970(&BasicInfo.ChangeTime, &PosixTime)) {
|
|
PosixTime = 0;
|
|
}
|
|
Fd->SystemOpenFileDesc->IoNode->ModifyIoNodeTime = PosixTime;
|
|
|
|
RtlLeaveCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
|
|
|
*pRetVal = FdIndex;
|
|
|
|
return IoOpenNewHandle(p, Fd, m);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxClose (
|
|
IN PPSX_PROCESS p,
|
|
IN OUT PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX Close.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the close request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_CLOSE_MSG args;
|
|
ULONG FdIndex;
|
|
|
|
args = &m->u.Close;
|
|
|
|
FdIndex = args->FileDes;
|
|
|
|
if (!ISFILEDESINRANGE(FdIndex)) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
if (!DeallocateFd(p, FdIndex)) {
|
|
|
|
//
|
|
// Bad File Descriptor
|
|
//
|
|
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
m->ReturnValue = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxPipe (
|
|
IN PPSX_PROCESS p,
|
|
IN OUT PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX Pipe.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the pipe request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_PIPE_MSG args;
|
|
PFILEDESCRIPTOR ReadFd,WriteFd;
|
|
ULONG ReadFdIndex,WriteFdIndex;
|
|
PLOCAL_PIPE Pipe;
|
|
PIONODE IoNode;
|
|
LARGE_INTEGER Time;
|
|
ULONG PosixTime;
|
|
|
|
args = &m->u.Pipe;
|
|
|
|
|
|
//
|
|
// Allocate two file descriptors. One for read, and one
|
|
// for write.
|
|
//
|
|
|
|
ReadFd = AllocateFd(p, 0, &ReadFdIndex);
|
|
if (NULL == ReadFd) {
|
|
|
|
//
|
|
// No file descriptors available
|
|
//
|
|
|
|
m->Error = EMFILE;
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Set FileDesc field so next allocate wont bump in to it
|
|
//
|
|
|
|
ReadFd->SystemOpenFileDesc = (PSYSTEMOPENFILE)1;
|
|
|
|
WriteFd = AllocateFd(p, 0, &WriteFdIndex);
|
|
if (NULL == WriteFd) {
|
|
|
|
//
|
|
// No file descriptors available
|
|
//
|
|
|
|
ReadFd->SystemOpenFileDesc = (PSYSTEMOPENFILE)NULL;
|
|
m->Error = EMFILE;
|
|
return TRUE;
|
|
}
|
|
|
|
Pipe = RtlAllocateHeap(PsxHeap, 0, sizeof(LOCAL_PIPE));
|
|
if (NULL == Pipe) {
|
|
DeallocateFd(p, ReadFdIndex);
|
|
DeallocateFd(p, WriteFdIndex);
|
|
m->Error = ENOMEM;
|
|
return TRUE;
|
|
}
|
|
|
|
ReadFd->SystemOpenFileDesc = AllocateSystemOpenFile();
|
|
if (! ReadFd->SystemOpenFileDesc) {
|
|
DeallocateFd(p, ReadFdIndex);
|
|
DeallocateFd(p, WriteFdIndex);
|
|
RtlFreeHeap(PsxHeap, 0, Pipe);
|
|
m->Error = ENOMEM;
|
|
return TRUE;
|
|
}
|
|
ReadFd->SystemOpenFileDesc->Flags = PSX_FD_READ;
|
|
ReadFd->SystemOpenFileDesc->NtIoHandle = (HANDLE)NULL;
|
|
|
|
WriteFd->SystemOpenFileDesc = AllocateSystemOpenFile();
|
|
if (! WriteFd->SystemOpenFileDesc) {
|
|
DeallocateSystemOpenFile(p, ReadFd->SystemOpenFileDesc);
|
|
DeallocateFd(p, ReadFdIndex);
|
|
DeallocateFd(p, WriteFdIndex);
|
|
RtlFreeHeap(PsxHeap, 0, Pipe);
|
|
m->Error = ENOMEM;
|
|
return TRUE;
|
|
}
|
|
WriteFd->SystemOpenFileDesc->Flags = PSX_FD_WRITE;
|
|
WriteFd->SystemOpenFileDesc->NtIoHandle = (HANDLE)NULL;
|
|
|
|
if (ReferenceOrCreateIoNode((dev_t)PSX_LOCAL_PIPE, (ULONG_PTR)Pipe,
|
|
FALSE, &ReadFd->SystemOpenFileDesc->IoNode)) {
|
|
Panic("PsxPipe: Existing IONODE ?\n");
|
|
} else {
|
|
DeallocateSystemOpenFile(p, ReadFd->SystemOpenFileDesc);
|
|
DeallocateSystemOpenFile(p, WriteFd->SystemOpenFileDesc);
|
|
DeallocateFd(p, ReadFdIndex);
|
|
DeallocateFd(p, WriteFdIndex);
|
|
RtlFreeHeap(PsxHeap, 0, Pipe);
|
|
m->Error = ENOMEM;
|
|
return TRUE;
|
|
}
|
|
|
|
WriteFd->SystemOpenFileDesc->IoNode = ReadFd->SystemOpenFileDesc->IoNode;
|
|
WriteFd->SystemOpenFileDesc->IoNode->ReferenceCount++;
|
|
|
|
if (! ReferenceOrCreateIoNode((dev_t)PSX_LOCAL_PIPE,
|
|
(ULONG_PTR)Pipe,
|
|
FALSE,
|
|
&WriteFd->SystemOpenFileDesc->IoNode)) {
|
|
// We don't bother to leave the ReadFd critsec because
|
|
// DereferenceIoNode will just destroy it anyway, and it's not
|
|
// like this code really cares about leaving the IoNode
|
|
// critsec properly anyway,, since it only releases it once
|
|
// later (which *does* work, but...).
|
|
DereferenceIoNode(ReadFd->SystemOpenFileDesc->IoNode);
|
|
DeallocateSystemOpenFile(p, ReadFd->SystemOpenFileDesc);
|
|
DeallocateSystemOpenFile(p, WriteFd->SystemOpenFileDesc);
|
|
DeallocateFd(p, ReadFdIndex);
|
|
DeallocateFd(p, WriteFdIndex);
|
|
RtlFreeHeap(PsxHeap, 0, Pipe);
|
|
m->Error = ENOMEM;
|
|
return TRUE;
|
|
}
|
|
|
|
IoNode = ReadFd->SystemOpenFileDesc->IoNode;
|
|
IoNode->Context = (PVOID)Pipe;
|
|
IoNode->IoVectors = &LocalPipeVectors;
|
|
IoNode->PathLength = 0;
|
|
|
|
//
|
|
// Note that all the following fields are 'implementation dependent' for
|
|
// local pipes except the times fields.
|
|
//
|
|
|
|
IoNode->Mode = (mode_t)0;
|
|
IoNode->OwnerId = p->EffectiveUid;
|
|
IoNode->GroupId = p->EffectiveGid;
|
|
|
|
NtQuerySystemTime(&Time);
|
|
if (!RtlTimeToSecondsSince1970(&Time, &PosixTime)) {
|
|
PosixTime = 0L; // Time not within range of 1970 - 2105
|
|
}
|
|
|
|
IoNode->AccessDataTime = IoNode->ModifyDataTime = IoNode->ModifyIoNodeTime =
|
|
PosixTime;
|
|
InitializeLocalPipe(Pipe);
|
|
|
|
RtlLeaveCriticalSection(&IoNode->IoNodeLock);
|
|
|
|
//
|
|
// call new handle routines
|
|
//
|
|
|
|
IoNewHandle(p, ReadFd);
|
|
IoNewHandle(p, WriteFd);
|
|
|
|
args->FileDes0 = ReadFdIndex;
|
|
args->FileDes1 = WriteFdIndex;
|
|
|
|
m->ReturnValue = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxWrite(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX write()
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the write request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_WRITE_MSG args;
|
|
PFILEDESCRIPTOR Fd;
|
|
|
|
args = &m->u.Write;
|
|
args->Command = IO_COMMAND_DONE;
|
|
|
|
Fd = FdIndexToFd(p,args->FileDes);
|
|
|
|
if (NULL == Fd) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
if (!(Fd->SystemOpenFileDesc->Flags & PSX_FD_WRITE)) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
if (0 == args->Nbytes) {
|
|
m->ReturnValue = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
args->Scratch1 = args->Scratch2 = 0;
|
|
return (Fd->SystemOpenFileDesc->IoNode->IoVectors->WriteRoutine)(p, m, Fd);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxRead(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX read()
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the read request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_READ_MSG args;
|
|
PFILEDESCRIPTOR Fd;
|
|
|
|
args = &m->u.Read;
|
|
args->Command = IO_COMMAND_DONE;
|
|
|
|
Fd = FdIndexToFd(p, args->FileDes);
|
|
if (NULL == Fd) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
if (!(Fd->SystemOpenFileDesc->Flags & PSX_FD_READ)) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
if (0 == args->Nbytes) {
|
|
m->ReturnValue = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
args->Scratch1 = args->Scratch2 = 0;
|
|
return (Fd->SystemOpenFileDesc->IoNode->IoVectors->ReadRoutine)(p, m, Fd);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxReadDir(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX read()
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the read request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_READDIR_MSG args;
|
|
PFILEDESCRIPTOR Fd;
|
|
|
|
args = &m->u.ReadDir;
|
|
|
|
Fd = FdIndexToFd(p, args->FileDes);
|
|
if (NULL == Fd) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
if (!(Fd->SystemOpenFileDesc->Flags & PSX_FD_READ)) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
if (0 == args->Nbytes) {
|
|
m->ReturnValue = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
return (Fd->SystemOpenFileDesc->IoNode->IoVectors->ReadRoutine)(p, m, Fd);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxDup(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX dup()
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_DUP_MSG args;
|
|
PFILEDESCRIPTOR Fd, FdDup;
|
|
ULONG FdIndex;
|
|
BOOLEAN RetVal;
|
|
|
|
args = &m->u.Dup;
|
|
|
|
Fd = FdIndexToFd(p, args->FileDes);
|
|
if (!Fd) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
FdDup = AllocateFd(p, 0, &FdIndex);
|
|
if (!Fd) {
|
|
|
|
//
|
|
// No file descriptors available
|
|
//
|
|
|
|
m->Error = EMFILE;
|
|
return TRUE;
|
|
|
|
}
|
|
RetVal = (Fd->SystemOpenFileDesc->IoNode->IoVectors->DupRoutine)
|
|
(p, m, Fd, FdDup);
|
|
m->ReturnValue = FdIndex;
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxDup2(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX dup2()
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_DUP2_MSG args;
|
|
PFILEDESCRIPTOR Fd, Fd2;
|
|
ULONG FdIndex, FdIndex2;
|
|
BOOLEAN RetVal;
|
|
|
|
args = &m->u.Dup2;
|
|
|
|
//
|
|
// If FileDes is not valid, or FileDes2 is out of range, return EBADF
|
|
//
|
|
|
|
Fd = FdIndexToFd(p, args->FileDes);
|
|
|
|
FdIndex = args->FileDes;
|
|
FdIndex2 = args->FileDes2;
|
|
|
|
if (!Fd || !ISFILEDESINRANGE(FdIndex2)) {
|
|
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// If FileDes is valid and == FileDes2, just return FileDes2
|
|
//
|
|
|
|
if (FdIndex == FdIndex2) {
|
|
|
|
m->ReturnValue = FdIndex2;
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Close FileDes2 (FdIndex2)
|
|
//
|
|
|
|
DeallocateFd(p, FdIndex2);
|
|
|
|
//
|
|
// Set Fd2 to file table entry just deallocated
|
|
//
|
|
|
|
Fd2 = &p->ProcessFileTable[FdIndex2];
|
|
|
|
// Call Dup Routine to do the work
|
|
|
|
RetVal = (Fd->SystemOpenFileDesc->IoNode->IoVectors->DupRoutine)
|
|
(p, m, Fd, Fd2);
|
|
m->ReturnValue = FdIndex2;
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxLseek(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX lseek()
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_LSEEK_MSG args;
|
|
PFILEDESCRIPTOR Fd;
|
|
|
|
args = &m->u.Lseek;
|
|
|
|
Fd = FdIndexToFd(p, args->FileDes);
|
|
|
|
if (!Fd) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Lseek is not allowed on FIFOs or local pipes
|
|
//
|
|
|
|
if (S_ISFIFO(Fd->SystemOpenFileDesc->IoNode->Mode) ||
|
|
Fd->SystemOpenFileDesc->IoNode->DeviceSerialNumber == PSX_LOCAL_PIPE) {
|
|
m->Error = ESPIPE;
|
|
return TRUE;
|
|
}
|
|
|
|
switch (args->Whence) {
|
|
case SEEK_SET:
|
|
case SEEK_CUR:
|
|
case SEEK_END:
|
|
break;
|
|
default:
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
return (Fd->SystemOpenFileDesc->IoNode->IoVectors->LseekRoutine)(p, m, Fd);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxUmask(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX umask.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the umask request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
{
|
|
PPSX_UMASK_MSG args;
|
|
mode_t NewMask;
|
|
|
|
args = &m->u.Umask;
|
|
|
|
// Save old creation mode mask to return
|
|
m->ReturnValue = (mode_t) (p->FileModeCreationMask);
|
|
|
|
// Mask off all but the permission bits in Cmask
|
|
NewMask = args->Cmask & _S_PROT;
|
|
|
|
// Zero old permission bits in Mode mask
|
|
p->FileModeCreationMask &= (!_S_PROT);
|
|
|
|
// Or in new permission bits
|
|
p->FileModeCreationMask |= NewMask;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxMkDir(
|
|
IN PPSX_PROCESS p,
|
|
IN OUT PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX mkdir.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the mkdir request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_MKDIR_MSG args;
|
|
HANDLE FileHandle;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
UNICODE_STRING Path_U;
|
|
ULONG DesiredAccess;
|
|
CHAR buf[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|
PSECURITY_DESCRIPTOR pSD = (PVOID)buf;
|
|
|
|
args = &m->u.MkDir;
|
|
|
|
//
|
|
// Check validity of pathname pointer
|
|
//
|
|
|
|
if (!ISPOINTERVALID_CLIENT(p,args->Path_U.Buffer,args->Path_U.Length)) {
|
|
KdPrint(("Invalid pointer to mkdir %lx \n",
|
|
args->Path_U.Buffer));
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
Path_U = args->Path_U;
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
Status = InitSecurityDescriptor(pSD, &args->Path_U, p->Process,
|
|
(args->Mode & _S_PROT) & ~p->FileModeCreationMask,
|
|
pvInitSDMem);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
EndImpersonation();
|
|
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, pSD);
|
|
|
|
DesiredAccess = WRITE_OWNER | WRITE_DAC;
|
|
|
|
Status = NtCreateFile(&FileHandle, DesiredAccess, &ObjA, &Iosb, NULL,
|
|
FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE,
|
|
FILE_DIRECTORY_FILE, NULL, 0);
|
|
|
|
EndImpersonation();
|
|
|
|
DeInitSecurityDescriptor(pSD, pvInitSDMem);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
(void)NtClose(FileHandle);
|
|
if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
|
|
m->Error = PsxStatusToErrnoPath(&Path_U);
|
|
return TRUE;
|
|
}
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
Status = NtClose(FileHandle);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxMkFifo(
|
|
IN PPSX_PROCESS p,
|
|
IN OUT PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX mkfifo.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the mkfifo request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_MKFIFO_MSG args;
|
|
HANDLE FileHandle;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
UNICODE_STRING Path_U;
|
|
ULONG DesiredAccess;
|
|
CHAR buf[SECURITY_DESCRIPTOR_MIN_LENGTH];
|
|
PSECURITY_DESCRIPTOR pSD = (PVOID)buf;
|
|
|
|
args = &m->u.MkFifo;
|
|
|
|
//
|
|
// Check validity of pathname pointer
|
|
//
|
|
|
|
if (!ISPOINTERVALID_CLIENT(p,args->Path_U.Buffer,args->Path_U.Length)) {
|
|
KdPrint(("Invalid pointer to mkfifo %lx\n",
|
|
args->Path_U.Buffer));
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
Path_U = args->Path_U;
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
Status = InitSecurityDescriptor(pSD, &args->Path_U, p->Process,
|
|
(args->Mode & _S_PROT) & ~p->FileModeCreationMask,
|
|
pvInitSDMem);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
EndImpersonation();
|
|
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, pSD);
|
|
|
|
DesiredAccess = FILE_READ_DATA | WRITE_DAC | WRITE_OWNER;
|
|
|
|
Status = NtCreateFile(&FileHandle, DesiredAccess, &ObjA, &Iosb,
|
|
NULL, FILE_ATTRIBUTE_SYSTEM, 0, FILE_CREATE, 0L,
|
|
NULL,
|
|
0);
|
|
|
|
EndImpersonation();
|
|
|
|
DeInitSecurityDescriptor(pSD, pvInitSDMem);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
|
|
m->Error = PsxStatusToErrnoPath(&Path_U);
|
|
return TRUE;
|
|
}
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
Status = NtClose(FileHandle);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxStat(
|
|
IN PPSX_PROCESS p,
|
|
IN OUT PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX stat.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the stat request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
{
|
|
PPSX_STAT_MSG args;
|
|
HANDLE FileHandle;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
UNICODE_STRING Path_U;
|
|
PIONODE IoNode;
|
|
FILE_INTERNAL_INFORMATION SerialNumber;
|
|
BOOLEAN RetVal;
|
|
|
|
args = &m->u.Stat;
|
|
|
|
//
|
|
// Check validity of pathname
|
|
//
|
|
|
|
if (!ISPOINTERVALID_CLIENT(p, args->Path_U.Buffer, args->Path_U.Length)) {
|
|
KdPrint(("Invalid pointer to stat %lx \n", args->Path_U.Buffer));
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
if (!ISPOINTERVALID_CLIENT(p, args->StatBuf, sizeof(struct stat))) {
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
Path_U = args->Path_U;
|
|
InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, NULL);
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
// Open the file to obtain file handle.
|
|
|
|
Status = NtOpenFile(&FileHandle,
|
|
SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES |
|
|
FILE_READ_EA, &ObjA, &Iosb,
|
|
SHARE_ALL,
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
EndImpersonation();
|
|
}
|
|
|
|
//
|
|
// Convert error code if open was not successful
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
|
|
m->Error = PsxStatusToErrnoPath(&Path_U);
|
|
return TRUE;
|
|
}
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Get file serial numbers...
|
|
//
|
|
|
|
Status = NtQueryInformationFile(FileHandle, &Iosb, &SerialNumber,
|
|
sizeof(SerialNumber),
|
|
FileInternalInformation);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("PSXSS: NtQueryInfoFile failed: 0x%x\n", Status));
|
|
}
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
//
|
|
// Find the Ionode associated with this file.
|
|
//
|
|
|
|
if (ReferenceOrCreateIoNode(GetFileDeviceNumber(&Path_U),
|
|
(ino_t)SerialNumber.IndexNumber.LowPart, TRUE, &IoNode)) {
|
|
|
|
RetVal = (IoNode->IoVectors->StatRoutine)(IoNode,
|
|
FileHandle, args->StatBuf, &Status);
|
|
RtlLeaveCriticalSection(&IoNode->IoNodeLock);
|
|
} else {
|
|
//
|
|
// Ionode doesn't exist. Not currently open or NonPosix file.
|
|
//
|
|
|
|
RetVal = (FileVectors.StatRoutine)(NULL, FileHandle,
|
|
args->StatBuf, &Status);
|
|
args->StatBuf->st_dev = GetFileDeviceNumber(&Path_U);
|
|
}
|
|
|
|
EndImpersonation();
|
|
NtClose(FileHandle);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxFStat(
|
|
IN PPSX_PROCESS p,
|
|
IN OUT PPSX_API_MSG m
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX fstat.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the fstat request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
{
|
|
PPSX_FSTAT_MSG args;
|
|
PFILEDESCRIPTOR Fd;
|
|
NTSTATUS Status;
|
|
BOOLEAN RetVal;
|
|
|
|
args = &m->u.FStat;
|
|
|
|
if (!ISPOINTERVALID_CLIENT(p, args->StatBuf, sizeof(struct stat))) {
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
Fd = FdIndexToFd(p, args->FileDes);
|
|
if (!Fd) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
RtlEnterCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
|
RetVal = (Fd->SystemOpenFileDesc->IoNode->IoVectors->StatRoutine)
|
|
(Fd->SystemOpenFileDesc->IoNode,
|
|
Fd->SystemOpenFileDesc->NtIoHandle,
|
|
args->StatBuf, &Status);
|
|
|
|
RtlLeaveCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxPathConf(
|
|
IN PPSX_PROCESS p,
|
|
IN OUT PPSX_API_MSG m
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX pathconf.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with
|
|
the pathconf request.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
{
|
|
PPSX_PATHCONF_MSG args;
|
|
HANDLE FileHandle;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
UNICODE_STRING Path;
|
|
ULONG Length;
|
|
PFILE_FS_ATTRIBUTE_INFORMATION pFSInfo;
|
|
unsigned char buf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION)+
|
|
128*sizeof(WCHAR)];
|
|
|
|
args = &m->u.PathConf;
|
|
pFSInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)buf;
|
|
|
|
//
|
|
// Check validity of pathname
|
|
//
|
|
|
|
if (!ISPOINTERVALID_CLIENT(p, args->Path.Buffer, args->Path.Length)) {
|
|
KdPrint(("Invalid pointer to pathconf: %lx \n", args->Path.Buffer));
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
Path = args->Path;
|
|
InitializeObjectAttributes(&ObjA, &Path, 0, NULL, NULL);
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
//
|
|
// Open the file to obtain file handle.
|
|
//
|
|
|
|
Status = NtOpenFile(&FileHandle,
|
|
SYNCHRONIZE | READ_CONTROL |
|
|
FILE_READ_ATTRIBUTES | FILE_READ_EA,
|
|
&ObjA,
|
|
&IoStatusBlock,
|
|
SHARE_ALL,
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
EndImpersonation();
|
|
}
|
|
|
|
//
|
|
// Convert error code if open was not successful
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
|
|
m->Error = PsxStatusToErrnoPath(&Path);
|
|
return TRUE;
|
|
}
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Figure out pathconf return value.
|
|
//
|
|
|
|
switch(args->Name) {
|
|
case _PC_LINK_MAX:
|
|
Status = NtQueryVolumeInformationFile(FileHandle,
|
|
&IoStatusBlock,
|
|
buf,
|
|
sizeof(buf),
|
|
FileFsAttributeInformation);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
if (pFSInfo->FileSystemNameLength > (sizeof(buf)-sizeof(WCHAR))) {
|
|
KdPrint(("PSXSS: File System Name too long in PsxPathConf\n"));
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
pFSInfo->FileSystemName[pFSInfo->FileSystemNameLength/2] = L'\0';
|
|
if (0 == wcscmp(L"NTFS", pFSInfo->FileSystemName) ||
|
|
0 == wcscmp(L"OFS", pFSInfo->FileSystemName)) {
|
|
m->ReturnValue = (ULONG)LINK_MAX;
|
|
} else {
|
|
m->ReturnValue = 1;
|
|
}
|
|
break;
|
|
|
|
case _PC_NAME_MAX:
|
|
Status = NtQueryVolumeInformationFile(FileHandle,
|
|
&IoStatusBlock,
|
|
buf,
|
|
sizeof(buf),
|
|
FileFsAttributeInformation);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
m->ReturnValue = pFSInfo->MaximumComponentNameLength;
|
|
break;
|
|
|
|
case _PC_PIPE_BUF:
|
|
m->ReturnValue = _POSIX_PIPE_BUF;
|
|
break;
|
|
|
|
case _PC_CHOWN_RESTRICTED:
|
|
m->ReturnValue = _POSIX_CHOWN_RESTRICTED;
|
|
break;
|
|
|
|
case _PC_NO_TRUNC:
|
|
m->ReturnValue = _POSIX_NO_TRUNC;
|
|
break;
|
|
|
|
case _PC_PATH_MAX:
|
|
m->ReturnValue = PATH_MAX;
|
|
break;
|
|
|
|
case _PC_MAX_CANON:
|
|
case _PC_MAX_INPUT:
|
|
case _PC_VDISABLE:
|
|
//
|
|
// No limit associated with file descriptor for these variables
|
|
//
|
|
m->Error = EINVAL;
|
|
break;
|
|
|
|
default:
|
|
m->Error = EINVAL;
|
|
}
|
|
|
|
Status = NtClose(FileHandle);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxFPathConf(
|
|
IN PPSX_PROCESS p,
|
|
IN OUT PPSX_API_MSG m
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX fpathconf.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with
|
|
the fpathconf request.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
{
|
|
PPSX_FPATHCONF_MSG args;
|
|
PFILEDESCRIPTOR Fd;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
ULONG Length;
|
|
PFILE_FS_ATTRIBUTE_INFORMATION pFSInfo;
|
|
unsigned char buf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION)+
|
|
128*sizeof(WCHAR)];
|
|
|
|
args = &m->u.FPathConf;
|
|
pFSInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)buf;
|
|
|
|
Fd = FdIndexToFd(p, args->FileDes);
|
|
if (!Fd) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
switch(args->Name) {
|
|
case _PC_LINK_MAX:
|
|
|
|
if (&FileVectors != Fd->SystemOpenFileDesc->IoNode->IoVectors) {
|
|
//
|
|
// The file descriptor is not open on a file.
|
|
//
|
|
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
Status = NtQueryVolumeInformationFile(
|
|
Fd->SystemOpenFileDesc->NtIoHandle,
|
|
&IoStatusBlock,
|
|
buf,
|
|
sizeof(buf),
|
|
FileFsAttributeInformation);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("PSXSS: NtqueryVolumeInformationFile failed: 0x%x\n", Status));
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
if (pFSInfo->FileSystemNameLength > (sizeof(buf)-sizeof(WCHAR))) {
|
|
KdPrint(("PSXSS: File System Name too long in PsxPathConf\n"));
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
pFSInfo->FileSystemName[pFSInfo->FileSystemNameLength/2] = L'\0';
|
|
if (0 == wcscmp(L"NTFS", pFSInfo->FileSystemName) ||
|
|
0 == wcscmp(L"OFS", pFSInfo->FileSystemName)) {
|
|
m->ReturnValue = (ULONG)(LINK_MAX); //
|
|
} else {
|
|
m->ReturnValue = 1;
|
|
}
|
|
break;
|
|
|
|
case _PC_NAME_MAX:
|
|
if (&FileVectors != Fd->SystemOpenFileDesc->IoNode->IoVectors) {
|
|
//
|
|
// The file descriptor is not open on a file.
|
|
//
|
|
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
Status = NtQueryVolumeInformationFile(
|
|
Fd->SystemOpenFileDesc->NtIoHandle,
|
|
&IoStatusBlock,
|
|
buf,
|
|
sizeof(buf),
|
|
FileFsAttributeInformation);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("PSXSS: NtqueryVolumeInformationFile failed: 0x%x\n", Status));
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
m->ReturnValue = pFSInfo->MaximumComponentNameLength;
|
|
break;
|
|
|
|
case _PC_PIPE_BUF:
|
|
m->ReturnValue = _POSIX_PIPE_BUF;
|
|
break;
|
|
|
|
case _PC_CHOWN_RESTRICTED:
|
|
m->ReturnValue = _POSIX_CHOWN_RESTRICTED;
|
|
break;
|
|
|
|
case _PC_NO_TRUNC:
|
|
m->ReturnValue = _POSIX_NO_TRUNC;
|
|
break;
|
|
|
|
case _PC_PATH_MAX:
|
|
m->ReturnValue = PATH_MAX;
|
|
break;
|
|
|
|
case _PC_MAX_CANON:
|
|
case _PC_MAX_INPUT:
|
|
case _PC_VDISABLE:
|
|
//
|
|
// No limit associated with file descriptor for these variables
|
|
//
|
|
m->Error = EINVAL;
|
|
break;
|
|
|
|
default:
|
|
m->Error = EINVAL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxChmod(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX chmod.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the chmod request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
{
|
|
PPSX_CHMOD_MSG args;
|
|
HANDLE FileHandle;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK
|
|
Iosb;
|
|
OBJECT_ATTRIBUTES
|
|
ObjA;
|
|
UNICODE_STRING
|
|
Path_U;
|
|
SECURITY_INFORMATION
|
|
SecurityInformation;
|
|
PSECURITY_DESCRIPTOR
|
|
SecurityDescriptor = NULL;
|
|
PACL pDacl = NULL;
|
|
ULONG DaclSize; // the size of the Dacl
|
|
PSID NtOwner, NtGroup;
|
|
BOOLEAN OwnerDefaulted, GroupDefaulted;
|
|
BOOLEAN DaclPresent, DaclDefaulted;
|
|
ACCESS_MASK
|
|
UserAccess, GroupAccess, OtherAccess;
|
|
ULONG LengthNeeded,
|
|
Revision, // Security Desc revision
|
|
SdSize; // Size for Security Desc
|
|
SECURITY_DESCRIPTOR_CONTROL
|
|
Control;
|
|
|
|
// Pointers for a manufactured absolute-format security descriptor.
|
|
|
|
PACL pAbsDacl = NULL,
|
|
pAbsSacl = NULL;
|
|
PSID pAbsOwner = NULL,
|
|
pAbsGroup = NULL;
|
|
|
|
args = &m->u.Chmod;
|
|
|
|
if (!ISPOINTERVALID_CLIENT(p, args->Path_U.Buffer,
|
|
args->Path_U.Length)) {
|
|
KdPrint(("Invalid pointer to chmod: %lx\n", args->Path_U.Buffer));
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
Path_U = args->Path_U;
|
|
InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, NULL);
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
Status = NtOpenFile(&FileHandle, SYNCHRONIZE | WRITE_DAC | READ_CONTROL,
|
|
&ObjA, &Iosb,
|
|
SHARE_ALL,
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
NTSTATUS st;
|
|
|
|
//
|
|
// 1003.1-90: EPERM when the euid does not match the
|
|
// owner of the file. We try to open the file with null
|
|
// access, if we can't do that then search permission is
|
|
// denied or somesuch. Otherwise, we give EPERM.
|
|
//
|
|
|
|
st = NtOpenFile(&FileHandle, SYNCHRONIZE | READ_CONTROL,
|
|
&ObjA, &Iosb,
|
|
SHARE_ALL,
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
EndImpersonation();
|
|
if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
|
|
m->Error = PsxStatusToErrnoPath(&Path_U);
|
|
return TRUE;
|
|
}
|
|
if (!NT_SUCCESS(st)) {
|
|
m->Error = PsxStatusToErrno(st);
|
|
return TRUE;
|
|
}
|
|
|
|
NtClose(FileHandle);
|
|
m->Error = EPERM;
|
|
return TRUE;
|
|
}
|
|
EndImpersonation();
|
|
|
|
|
|
//
|
|
// Get the security descriptor for the file.
|
|
//
|
|
|
|
SecurityInformation = OWNER_SECURITY_INFORMATION |
|
|
GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
|
|
|
|
Status = NtQuerySecurityObject(FileHandle, SecurityInformation,
|
|
NULL, 0, &SdSize);
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
|
|
|
|
SecurityDescriptor = RtlAllocateHeap(PsxHeap, 0, SdSize);
|
|
if (NULL == SecurityDescriptor) {
|
|
m->Error = ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
Status = NtQuerySecurityObject(FileHandle, SecurityInformation,
|
|
SecurityDescriptor, SdSize, &SdSize);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlGetControlSecurityDescriptor(SecurityDescriptor,
|
|
&Control, &Revision);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
ASSERT(SECURITY_DESCRIPTOR_REVISION == Revision);
|
|
|
|
if (Control & SE_SELF_RELATIVE) {
|
|
PSECURITY_DESCRIPTOR
|
|
AbsSD; // SD in absolute format.
|
|
|
|
ULONG AbsSdSize = 0,
|
|
DaclSize = 0,
|
|
SaclSize = 0,
|
|
OwnerSize = 0,
|
|
GroupSize = 0;
|
|
|
|
//
|
|
// This security descriptor needs to be converted to absolute
|
|
// format.
|
|
//
|
|
|
|
Status = RtlSelfRelativeToAbsoluteSD(SecurityDescriptor,
|
|
NULL, &AbsSdSize, NULL, &DaclSize, NULL, &SaclSize,
|
|
NULL, &OwnerSize, NULL, &GroupSize);
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
|
|
|
|
AbsSD = RtlAllocateHeap(PsxHeap, 0, AbsSdSize);
|
|
pAbsDacl = RtlAllocateHeap(PsxHeap, 0, DaclSize);
|
|
pAbsSacl = RtlAllocateHeap(PsxHeap, 0, SaclSize);
|
|
pAbsOwner = RtlAllocateHeap(PsxHeap, 0, OwnerSize);
|
|
pAbsGroup = RtlAllocateHeap(PsxHeap, 0, GroupSize);
|
|
|
|
if (NULL == AbsSD || NULL == pAbsDacl || NULL == pAbsSacl
|
|
|| NULL == pAbsOwner || NULL == pAbsGroup) {
|
|
m->Error = ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
Status = RtlSelfRelativeToAbsoluteSD(SecurityDescriptor,
|
|
AbsSD, &AbsSdSize, pAbsDacl, &DaclSize, pAbsSacl,
|
|
&SaclSize, pAbsOwner, &OwnerSize, pAbsGroup,
|
|
&GroupSize);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
// RtlFreeHeap(PsxHeap, 0, SecurityDescriptor);
|
|
SecurityDescriptor = AbsSD;
|
|
AbsSD = NULL; // so it won't be freed later
|
|
}
|
|
|
|
//
|
|
// Get the owner and group from the security descriptor
|
|
//
|
|
|
|
Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
|
|
&NtOwner, &OwnerDefaulted);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlGetGroupSecurityDescriptor(SecurityDescriptor,
|
|
&NtGroup, &GroupDefaulted);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
if (NULL == NtOwner || NULL == NtGroup) {
|
|
//
|
|
// We need an owner and group to change the modes; fail.
|
|
//
|
|
KdPrint(("PsxChmod: No owner or no group\n"));
|
|
m->Error = EPERM;
|
|
goto out;
|
|
}
|
|
|
|
Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
|
|
&DaclPresent, &pDacl, &DaclDefaulted);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
ModeToAccessMask(args->Mode, &UserAccess, &GroupAccess, &OtherAccess);
|
|
|
|
Status = RtlMakePosixAcl(ACL_REVISION2, NtOwner, NtGroup, UserAccess,
|
|
GroupAccess, OtherAccess, 0, NULL, &LengthNeeded);
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
|
|
|
|
pDacl = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
|
|
if (NULL == pDacl) {
|
|
m->Error = ENOMEM;
|
|
return TRUE;
|
|
}
|
|
|
|
Status = RtlMakePosixAcl(ACL_REVISION2, NtOwner, NtGroup, UserAccess,
|
|
GroupAccess, OtherAccess, LengthNeeded, pDacl, &DaclSize);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE,
|
|
pDacl, FALSE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("PSXSS: RtlSetDacl: 0x%x\n", Status));
|
|
m->Error = EPERM;
|
|
return TRUE;
|
|
}
|
|
|
|
SecurityInformation = DACL_SECURITY_INFORMATION;
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = NtSetSecurityObject(FileHandle, SecurityInformation,
|
|
SecurityDescriptor);
|
|
EndImpersonation();
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
}
|
|
|
|
out:
|
|
NtClose(FileHandle);
|
|
|
|
if (NULL != pAbsDacl) {
|
|
RtlFreeHeap(PsxHeap, 0, pAbsDacl);
|
|
}
|
|
if (NULL != pAbsSacl) {
|
|
RtlFreeHeap(PsxHeap, 0, pAbsSacl);
|
|
}
|
|
if (NULL != pAbsOwner) {
|
|
RtlFreeHeap(PsxHeap, 0, pAbsOwner);
|
|
}
|
|
if (NULL != pAbsGroup) {
|
|
RtlFreeHeap(PsxHeap, 0, pAbsGroup);
|
|
}
|
|
if (NULL != SecurityDescriptor) {
|
|
RtlFreeHeap(PsxHeap, 0, SecurityDescriptor);
|
|
}
|
|
if (NULL != pDacl) {
|
|
RtlFreeHeap(PsxHeap, 0, pDacl);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxChown(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX chown.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the chown request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
{
|
|
PPSX_CHOWN_MSG args;
|
|
HANDLE FileHandle;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
UNICODE_STRING Path_U;
|
|
PIONODE IoNode;
|
|
SECURITY_INFORMATION SecurityInformation;
|
|
PSECURITY_DESCRIPTOR
|
|
SecurityDescriptor = NULL,
|
|
pFreeSD = NULL;
|
|
ACCESS_MASK UserAccess, GroupAccess, OtherAccess;
|
|
ULONG LengthNeeded;
|
|
PSID NtOwner, // owner from existing SD
|
|
NtGroup, // group from existing SD
|
|
DomainSid, // domain goes with new gid
|
|
NewGroup = NULL, // new group from DomainSid+gid
|
|
NewUser = NULL; // new user
|
|
BOOLEAN OwnerDefaulted, GroupDefaulted, DaclPresent, DaclDefaulted;
|
|
PACL pDacl = NULL, pDacl2 = NULL;
|
|
ULONG Revision; // Security Desc revision
|
|
SECURITY_DESCRIPTOR_CONTROL
|
|
Control;
|
|
FILE_INTERNAL_INFORMATION
|
|
SerialNumber;
|
|
|
|
// Pointers for a manufactured absolute-format security descriptor.
|
|
|
|
PACL pAbsDacl = NULL,
|
|
pAbsSacl = NULL;
|
|
PSID pAbsOwner = NULL,
|
|
pAbsGroup = NULL;
|
|
|
|
args = &m->u.Chown;
|
|
|
|
if (!ISPOINTERVALID_CLIENT(p, args->Path_U.Buffer,
|
|
args->Path_U.Length)) {
|
|
KdPrint(("Invalid pointer to chown: %lx\n",
|
|
args->Path_U.Buffer));
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
Path_U = args->Path_U;
|
|
InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, NULL);
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
Status = NtOpenFile(&FileHandle,
|
|
SYNCHRONIZE | READ_CONTROL | WRITE_OWNER | WRITE_DAC,
|
|
&ObjA, &Iosb,
|
|
SHARE_ALL,
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
EndImpersonation();
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
//
|
|
// 1003.1-90 (5.6.5.4): EPERM when the caller does not have
|
|
// permission to change the owner. We check this by opening
|
|
// the file with the same mode, except without WRITE_OWNER.
|
|
//
|
|
|
|
if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
|
|
m->Error = PsxStatusToErrnoPath(&Path_U);
|
|
} else {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
}
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
Status = NtOpenFile(&FileHandle,
|
|
SYNCHRONIZE | READ_CONTROL,
|
|
&ObjA, &Iosb,
|
|
SHARE_ALL,
|
|
FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
EndImpersonation();
|
|
if (NT_SUCCESS(Status)) {
|
|
m->Error = EPERM;
|
|
NtClose(FileHandle);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Get serial numbers.
|
|
//
|
|
|
|
Status = NtQueryInformationFile(FileHandle, &Iosb, &SerialNumber,
|
|
sizeof(SerialNumber), FileInternalInformation);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
if (ReferenceOrCreateIoNode(GetFileDeviceNumber(&Path_U),
|
|
(ino_t)SerialNumber.IndexNumber.LowPart, TRUE, &IoNode)) {
|
|
// File already is open.
|
|
} else {
|
|
IoNode = NULL;
|
|
}
|
|
|
|
//
|
|
// Get SecurityInformation for the file.
|
|
//
|
|
|
|
SecurityInformation = OWNER_SECURITY_INFORMATION |
|
|
GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
|
|
|
|
Status = NtQuerySecurityObject(FileHandle, SecurityInformation,
|
|
NULL, 0, &LengthNeeded);
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
|
|
|
|
SecurityDescriptor = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
|
|
if (NULL == SecurityDescriptor) {
|
|
m->Error = ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
Status = NtQuerySecurityObject(FileHandle, SecurityInformation,
|
|
SecurityDescriptor, LengthNeeded, &LengthNeeded);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlGetControlSecurityDescriptor(SecurityDescriptor,
|
|
&Control, &Revision);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
ASSERT(SECURITY_DESCRIPTOR_REVISION == Revision);
|
|
|
|
if (Control & SE_SELF_RELATIVE) {
|
|
PSECURITY_DESCRIPTOR
|
|
AbsSD; // SD in absolute format.
|
|
|
|
ULONG AbsSdSize = 0,
|
|
DaclSize = 0, SaclSize = 0,
|
|
OwnerSize = 0, GroupSize = 0;
|
|
|
|
//
|
|
// This security descriptor needs to be converted to absolute
|
|
// format.
|
|
//
|
|
|
|
Status = RtlSelfRelativeToAbsoluteSD(SecurityDescriptor,
|
|
NULL, &AbsSdSize, NULL, &DaclSize, NULL, &SaclSize,
|
|
NULL, &OwnerSize, NULL, &GroupSize);
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
|
|
|
|
AbsSD = RtlAllocateHeap(PsxHeap, 0, AbsSdSize);
|
|
pAbsSacl = RtlAllocateHeap(PsxHeap, 0, SaclSize);
|
|
pAbsOwner = RtlAllocateHeap(PsxHeap, 0, OwnerSize);
|
|
pAbsGroup = RtlAllocateHeap(PsxHeap, 0, GroupSize);
|
|
pAbsDacl = RtlAllocateHeap(PsxHeap, 0, DaclSize);
|
|
|
|
if (NULL == AbsSD || NULL == pAbsDacl || NULL == pAbsSacl
|
|
|| NULL == pAbsOwner || NULL == pAbsGroup) {
|
|
m->Error = ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
Status = RtlSelfRelativeToAbsoluteSD(SecurityDescriptor,
|
|
AbsSD, &AbsSdSize, pAbsDacl, &DaclSize, pAbsSacl,
|
|
&SaclSize, pAbsOwner, &OwnerSize, pAbsGroup,
|
|
&GroupSize);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
pFreeSD = SecurityDescriptor;
|
|
SecurityDescriptor = AbsSD;
|
|
}
|
|
|
|
//
|
|
// Get the owner and group from the security descriptor
|
|
//
|
|
|
|
Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
|
|
&NtOwner, &OwnerDefaulted);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlGetGroupSecurityDescriptor(SecurityDescriptor,
|
|
&NtGroup, &GroupDefaulted);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
if (NULL == NtOwner || NULL == NtGroup) {
|
|
//
|
|
// Seems like this file doesn't have an owner or a
|
|
// group, which means that we can't change it's group.
|
|
//
|
|
// XXX.mjb: ideally, would make the file owned by us if
|
|
// possible.
|
|
//
|
|
KdPrint(("PSXSS: PsxChown: no owner or no group\n"));
|
|
m->Error = EPERM;
|
|
goto out;
|
|
}
|
|
|
|
Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
|
|
&DaclPresent, &pDacl, &DaclDefaulted);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
if (!DaclPresent || (DaclPresent && NULL == pDacl)) {
|
|
|
|
//
|
|
// All access is allowed to this file. We attach a Posix-
|
|
// type acl that allows all access.
|
|
//
|
|
|
|
ModeToAccessMask(0777, &UserAccess, &GroupAccess, &OtherAccess);
|
|
|
|
} else {
|
|
Status = RtlInterpretPosixAcl(ACL_REVISION2, NtOwner, NtGroup,
|
|
pDacl, &UserAccess, &GroupAccess, &OtherAccess);
|
|
if (STATUS_COULD_NOT_INTERPRET == Status) {
|
|
//
|
|
// There is an acl, but it is not in the Posix form.
|
|
// Ideally, we'd like to leave the resulting file
|
|
// with an ACL approximating the one we've foud there,
|
|
// but that's hard so we'll just do the easy thing.
|
|
//
|
|
|
|
ModeToAccessMask(0777, &UserAccess, &GroupAccess,
|
|
&OtherAccess);
|
|
} else if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("PSXSS: RtlInterpretPosixAcl: 0x%x\n", Status));
|
|
m->Error = EPERM;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (0xFFF == args->Group) {
|
|
//
|
|
// The login group is treated specially here.
|
|
//
|
|
|
|
NewGroup = GetLoginGroupSid(p);
|
|
if (NULL == NewGroup) {
|
|
m->Error = ENOMEM;
|
|
goto out;
|
|
}
|
|
} else {
|
|
|
|
DomainSid = GetSidByOffset(args->Group & 0xFFFF0000);
|
|
if (NULL == DomainSid) {
|
|
|
|
//
|
|
// Either we can't get to the domain, or the user
|
|
// specified an invalid group. Bad.
|
|
//
|
|
m->Error = EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
NewGroup = MakeSid(DomainSid, args->Group & 0xFFFF);
|
|
if (NULL == NewGroup) {
|
|
m->Error = ENOMEM;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
DomainSid = GetSidByOffset(args->Owner & 0xFFFF0000);
|
|
if (NULL == DomainSid) {
|
|
m->Error = EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
NewUser = MakeSid(DomainSid, args->Owner & 0xFFFF);
|
|
if (NULL == NewUser) {
|
|
m->Error = ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
Status = RtlMakePosixAcl(ACL_REVISION2, NewUser, NewGroup,
|
|
UserAccess, GroupAccess, OtherAccess, 0, NULL, &LengthNeeded);
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
|
|
|
|
pDacl2 = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
|
|
if (NULL == pDacl2) {
|
|
m->Error = ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
Status = RtlMakePosixAcl(ACL_REVISION2, NewUser, NewGroup,
|
|
UserAccess, GroupAccess, OtherAccess, LengthNeeded, pDacl2,
|
|
&LengthNeeded);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor, TRUE,
|
|
pDacl2, FALSE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("PSXSS: PsxChown: RtlSetDacl: 0x%x\n", Status));
|
|
m->Error = EPERM;
|
|
goto out;
|
|
}
|
|
|
|
Status = RtlSetGroupSecurityDescriptor(SecurityDescriptor, NewGroup, FALSE);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlSetOwnerSecurityDescriptor(SecurityDescriptor, NewUser, FALSE);
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = NtSetSecurityObject(FileHandle, SecurityInformation,
|
|
SecurityDescriptor);
|
|
EndImpersonation();
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
goto out;
|
|
}
|
|
|
|
if (NULL != IoNode) {
|
|
IoNode->GroupId = args->Group;
|
|
}
|
|
|
|
out:
|
|
NtClose(FileHandle);
|
|
|
|
if (NULL != SecurityDescriptor) {
|
|
RtlFreeHeap(PsxHeap, 0, SecurityDescriptor);
|
|
}
|
|
if (NULL != NewGroup) {
|
|
RtlFreeHeap(PsxHeap, 0, NewGroup);
|
|
}
|
|
if (NULL != NewUser) {
|
|
RtlFreeHeap(PsxHeap, 0, NewUser);
|
|
}
|
|
if (NULL != pDacl2) {
|
|
RtlFreeHeap(PsxHeap, 0, pDacl2);
|
|
}
|
|
if (NULL != pAbsDacl) {
|
|
RtlFreeHeap(PsxHeap, 0, pAbsDacl);
|
|
}
|
|
if (NULL != pAbsSacl) {
|
|
RtlFreeHeap(PsxHeap, 0, pAbsSacl);
|
|
}
|
|
if (NULL != pAbsOwner) {
|
|
RtlFreeHeap(PsxHeap, 0, pAbsOwner);
|
|
}
|
|
if (NULL != pAbsGroup) {
|
|
RtlFreeHeap(PsxHeap, 0, pAbsGroup);
|
|
}
|
|
if (NULL != pFreeSD) {
|
|
RtlFreeHeap(PsxHeap, 0, pFreeSD);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
PsxUtime(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX utime.
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the utime request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
{
|
|
PPSX_UTIME_MSG args;
|
|
HANDLE FileHandle;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
UNICODE_STRING Path_U;
|
|
FILE_BASIC_INFORMATION BasicInfo;
|
|
LARGE_INTEGER Time;
|
|
|
|
args = &m->u.Utime;
|
|
|
|
if (!ISPOINTERVALID_CLIENT(p,args->Path_U.Buffer,args->Path_U.Length)) {
|
|
KdPrint(("Invalid pointer to utime %lx\n",
|
|
args->Path_U.Buffer));
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
|
|
Path_U = args->Path_U;
|
|
|
|
InitializeObjectAttributes(&ObjA, &Path_U, 0, NULL, NULL);
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = NtOpenFile(&FileHandle,
|
|
SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES,
|
|
&ObjA, &Iosb, SHARE_ALL, FILE_SYNCHRONOUS_IO_NONALERT);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
EndImpersonation();
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (STATUS_OBJECT_PATH_NOT_FOUND == Status) {
|
|
m->Error = PsxStatusToErrnoPath(&Path_U);
|
|
return TRUE;
|
|
}
|
|
m->Error = PsxStatusToErrno(Status);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// 1003.1-1990: EPERM when the /times/ argument is not
|
|
// NULL, the calling process has write access to the file,
|
|
// but is not the owner of the file. Here we're denying
|
|
// access to the file that NT would grant.
|
|
//
|
|
|
|
if (NULL != args->TimesSpecified) {
|
|
struct stat StatBuf;
|
|
|
|
StatBuf.st_uid = 0; // in case FindOwnerModeFile fails
|
|
FindOwnerModeFile(FileHandle, &StatBuf);
|
|
|
|
if (StatBuf.st_uid != p->EffectiveUid) {
|
|
UCHAR buf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) +
|
|
128 * sizeof(WCHAR)];
|
|
PFILE_FS_ATTRIBUTE_INFORMATION pFSInfo = (PVOID)buf;
|
|
|
|
// We ignore this test for all but NTFS
|
|
|
|
Status = NtQueryVolumeInformationFile(FileHandle,
|
|
&Iosb, buf, sizeof(buf),
|
|
FileFsAttributeInformation);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
pFSInfo->FileSystemName[pFSInfo->FileSystemNameLength/2] = 0;
|
|
if (0 == wcscmp(L"NTFS", pFSInfo->FileSystemName) ||
|
|
0 == wcscmp(L"OFS", pFSInfo->FileSystemName)) {
|
|
|
|
NtClose(FileHandle);
|
|
m->Error = EPERM;
|
|
EndImpersonation();
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
EndImpersonation();
|
|
|
|
RtlZeroMemory(&Time, sizeof(Time));
|
|
BasicInfo.CreationTime = Time;
|
|
BasicInfo.ChangeTime = Time;
|
|
BasicInfo.FileAttributes = 0;
|
|
|
|
//
|
|
// If the utimbuf is NULL, we're to set the file times to the current
|
|
// time. The owner and anyone else with write permission on the file
|
|
// should be able to perform this operation. If times are specified
|
|
// via a utimbuf, only the owner should be able to perform the
|
|
// operation.
|
|
//
|
|
|
|
if (args->TimesSpecified == NULL) {
|
|
NtQuerySystemTime(&Time);
|
|
|
|
BasicInfo.LastAccessTime = Time;
|
|
BasicInfo.LastWriteTime = Time;
|
|
} else {
|
|
RtlSecondsSince1970ToTime((ULONG)(args->Times.actime), &Time);
|
|
BasicInfo.LastAccessTime = Time;
|
|
|
|
RtlSecondsSince1970ToTime((ULONG)(args->Times.modtime), &Time);
|
|
BasicInfo.LastWriteTime = Time;
|
|
}
|
|
|
|
Status = NtImpersonateClientOfPort(p->ClientPort, (PPORT_MESSAGE)m);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = NtSetInformationFile(FileHandle, &Iosb, &BasicInfo,
|
|
sizeof(BasicInfo), FileBasicInformation);
|
|
|
|
EndImpersonation();
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
//FALL OUT
|
|
}
|
|
|
|
NtClose(FileHandle);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
PsxFcntl(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX fcntl().
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
FALSE - No reply should be sent, for the case in which the process
|
|
was blocked (as in F_SETLKW).
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_FCNTL_MSG args;
|
|
PFILEDESCRIPTOR pFd, pFdDup;
|
|
NTSTATUS Status;
|
|
BOOLEAN b;
|
|
int error;
|
|
|
|
args = &m->u.Fcntl;
|
|
|
|
pFd = FdIndexToFd(p, args->FileDes);
|
|
if (NULL == pFd) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
switch (args->Command) {
|
|
case F_DUPFD:
|
|
if (!ISFILEDESINRANGE(args->u.i)) {
|
|
m->Error = EINVAL;
|
|
return TRUE;
|
|
}
|
|
pFdDup = AllocateFd(p, args->u.i, &m->ReturnValue);
|
|
if (NULL == pFdDup) {
|
|
// no descriptors are available
|
|
m->Error = EMFILE;
|
|
return TRUE;
|
|
}
|
|
ASSERT(NULL != pFd->SystemOpenFileDesc->IoNode->IoVectors->DupRoutine);
|
|
return (pFd->SystemOpenFileDesc->IoNode->IoVectors->DupRoutine)
|
|
(p, m, pFd, pFdDup);
|
|
case F_GETFD:
|
|
//
|
|
// File descriptor flags
|
|
//
|
|
|
|
m->ReturnValue = 0;
|
|
if (pFd->Flags & PSX_FD_CLOSE_ON_EXEC) {
|
|
m->ReturnValue |= FD_CLOEXEC;
|
|
}
|
|
return TRUE;
|
|
case F_SETFD:
|
|
pFd->Flags = 0;
|
|
if (args->u.i & FD_CLOEXEC) {
|
|
pFd->Flags |= PSX_FD_CLOSE_ON_EXEC;
|
|
}
|
|
m->ReturnValue = 0;
|
|
return TRUE;
|
|
|
|
case F_GETFL:
|
|
//
|
|
// Get file description flags
|
|
//
|
|
if ((pFd->SystemOpenFileDesc->Flags &
|
|
(PSX_FD_READ | PSX_FD_WRITE))
|
|
== (PSX_FD_READ | PSX_FD_WRITE)) {
|
|
m->ReturnValue |= O_RDWR;
|
|
} else if (pFd->SystemOpenFileDesc->Flags & PSX_FD_READ) {
|
|
m->ReturnValue |= O_RDONLY;
|
|
} else if (pFd->SystemOpenFileDesc->Flags & PSX_FD_WRITE) {
|
|
m->ReturnValue |= O_WRONLY;
|
|
}
|
|
if (pFd->SystemOpenFileDesc->Flags & PSX_FD_NOBLOCK) {
|
|
m->ReturnValue |= O_NONBLOCK;
|
|
}
|
|
if (pFd->SystemOpenFileDesc->Flags & PSX_FD_APPEND) {
|
|
m->ReturnValue |= O_APPEND;
|
|
}
|
|
return TRUE;
|
|
case F_SETFL:
|
|
pFd->SystemOpenFileDesc->Flags &= ~(PSX_FD_APPEND | PSX_FD_NOBLOCK);
|
|
if (args->u.i & O_APPEND) {
|
|
pFd->SystemOpenFileDesc->Flags |= PSX_FD_APPEND;
|
|
}
|
|
if (args->u.i & O_NONBLOCK) {
|
|
pFd->SystemOpenFileDesc->Flags |= PSX_FD_NOBLOCK;
|
|
}
|
|
m->ReturnValue = 0;
|
|
return TRUE;
|
|
|
|
case F_SETLK:
|
|
case F_SETLKW:
|
|
//
|
|
// 1003.1-90 (6.5.2.4): EBADF if F_SETLK or F_SETLKW and
|
|
// l_type is F_RDLCK and fildes is not ... open for reading.
|
|
//
|
|
|
|
if (F_RDLCK == args->u.pf->l_type &&
|
|
!(pFd->SystemOpenFileDesc->Flags & PSX_FD_READ)) {
|
|
m->Error = EBADF;
|
|
m->ReturnValue = (ULONG)(-1);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// ... EBADF if F_SETLK or F_SETLKW and l_type is F_WRLCK
|
|
// and fildes is not ... open for writing.
|
|
//
|
|
|
|
if (F_WRLCK == args->u.pf->l_type &&
|
|
!(pFd->SystemOpenFileDesc->Flags & PSX_FD_WRITE)) {
|
|
m->Error = EBADF;
|
|
m->ReturnValue = (ULONG)(-1);
|
|
return TRUE;
|
|
}
|
|
|
|
//FALLTHROUGH
|
|
|
|
case F_GETLK:
|
|
|
|
if (!(pFd->SystemOpenFileDesc->IoNode->Mode & S_IFREG)) {
|
|
//
|
|
// flocks only work on regular files
|
|
//
|
|
|
|
m->Error = EINVAL;
|
|
m->ReturnValue = (ULONG)(-1);
|
|
}
|
|
|
|
RtlEnterCriticalSection(&pFd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
|
|
|
b = DoFlockStuff(p, m, args->Command, pFd,
|
|
args->u.pf, &error);
|
|
|
|
if (b) {
|
|
RtlLeaveCriticalSection(&pFd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
|
}
|
|
|
|
m->Error = error;
|
|
if (error == 0) {
|
|
m->ReturnValue = 0;
|
|
} else {
|
|
m->ReturnValue = (ULONG)(-1);
|
|
}
|
|
//
|
|
// DoFlockStuff returns FALSE if the process was
|
|
// blocked and no reply should be sent.
|
|
//
|
|
return b;
|
|
#if DBG
|
|
case 99:
|
|
DumpFlockList(pFd->SystemOpenFileDesc->IoNode);
|
|
break;
|
|
#endif
|
|
default:
|
|
// This shouldn't happen; the client checks for valid
|
|
// command arguments.
|
|
|
|
ASSERT(0);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
PsxIsatty(
|
|
IN PPSX_PROCESS p,
|
|
IN OUT PPSX_API_MSG m
|
|
)
|
|
{
|
|
PPSX_ISATTY_MSG args;
|
|
NTSTATUS Status;
|
|
PFILEDESCRIPTOR Fd;
|
|
|
|
args = &m->u.Isatty;
|
|
|
|
Fd = FdIndexToFd(p, args->FileDes);
|
|
if (!Fd) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
if (&ConVectors == Fd->SystemOpenFileDesc->IoNode->IoVectors) {
|
|
//
|
|
// If the fd is open on the console, it's not
|
|
// necessarily a tty, since the console session manager
|
|
// could have redirected the output. The dll will send
|
|
// a message to posix.exe, asking whether it's redirected
|
|
// or not.
|
|
//
|
|
args->Command = IO_COMMAND_DO_CONSIO;
|
|
args->FileDes = HandleToUlong(Fd->SystemOpenFileDesc->NtIoHandle);
|
|
return TRUE;
|
|
}
|
|
args->Command = IO_COMMAND_DONE;
|
|
|
|
m->ReturnValue = FALSE; // not a tty
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
PsxFtruncate(
|
|
IN PPSX_PROCESS p,
|
|
IN PPSX_API_MSG m
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure implements POSIX ftruncate().
|
|
|
|
Arguments:
|
|
|
|
p - Supplies the address of the process making the call.
|
|
|
|
m - Supplies the address of the message associated with the request.
|
|
|
|
Return Value:
|
|
|
|
TRUE - The contents of *m should be used to generate a reply.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPSX_FTRUNCATE_MSG args;
|
|
PFILEDESCRIPTOR Fd;
|
|
FILE_END_OF_FILE_INFORMATION EofInfo;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
args = &m->u.Ftruncate;
|
|
|
|
Fd = FdIndexToFd(p, args->FileDes);
|
|
|
|
if (!Fd) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Ftruncate is only allowed on regular files.
|
|
//
|
|
|
|
if (S_ISFIFO(Fd->SystemOpenFileDesc->IoNode->Mode) ||
|
|
Fd->SystemOpenFileDesc->IoNode->DeviceSerialNumber == PSX_LOCAL_PIPE) {
|
|
m->Error = ESPIPE;
|
|
return TRUE;
|
|
}
|
|
|
|
if (&FileVectors != Fd->SystemOpenFileDesc->IoNode->IoVectors) {
|
|
m->Error = EBADF;
|
|
return TRUE;
|
|
}
|
|
|
|
EofInfo.EndOfFile.QuadPart = args->Length;
|
|
|
|
Status = NtSetInformationFile(
|
|
Fd->SystemOpenFileDesc->NtIoHandle,
|
|
&iosb,
|
|
(PVOID)&EofInfo,
|
|
sizeof(EofInfo),
|
|
FileEndOfFileInformation
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
m->Error = PsxStatusToErrno(Status);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
// InitSecurityDescriptor -- to be called when a new file is created. Sets
|
|
// up the security descriptor appropriately.
|
|
//
|
|
// The filename is used only to get the name of the parent direcotory,
|
|
// which we use to set the group in the security descriptor.
|
|
//
|
|
|
|
NTSTATUS
|
|
InitSecurityDescriptor(
|
|
PSECURITY_DESCRIPTOR pSD,
|
|
PUNICODE_STRING pFileName,
|
|
IN HANDLE Process,
|
|
IN mode_t Mode,
|
|
OUT PVOID *pvMem
|
|
)
|
|
{
|
|
PSID_AND_ATTRIBUTES
|
|
pSA;
|
|
HANDLE TokenHandle;
|
|
ULONG Length, LengthNeeded;
|
|
NTSTATUS
|
|
Status;
|
|
PACL pDacl;
|
|
ACCESS_MASK
|
|
UserAccess,
|
|
GroupAccess,
|
|
OtherAccess;
|
|
ANSI_STRING File_A;
|
|
UNICODE_STRING ParentDir_U;
|
|
OBJECT_ATTRIBUTES Obj;
|
|
HANDLE DirHandle;
|
|
PSID DirGroup;
|
|
PCHAR pch;
|
|
IO_STATUS_BLOCK Iosb;
|
|
SECURITY_INFORMATION SecurityInformation;
|
|
PSECURITY_DESCRIPTOR pDirSD = NULL;
|
|
PTOKEN_PRIMARY_GROUP pGroup = NULL;
|
|
BOOLEAN Defaulted;
|
|
int i;
|
|
|
|
Status = RtlUnicodeStringToAnsiString(&File_A, pFileName, TRUE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Open the parent directory and get its group owner.
|
|
//
|
|
|
|
pch = strrchr(File_A.Buffer, '\\') + 1;
|
|
if (pch == NULL)
|
|
return STATUS_OBJECT_PATH_SYNTAX_BAD;
|
|
*pch = '\0';
|
|
File_A.Length = (USHORT)strlen(File_A.Buffer);
|
|
|
|
Status = RtlAnsiStringToUnicodeString(&ParentDir_U, &File_A, TRUE);
|
|
RtlFreeAnsiString(&File_A);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
InitializeObjectAttributes(&Obj, &ParentDir_U, 0, NULL, NULL);
|
|
Status = NtOpenFile(&DirHandle,
|
|
SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES |
|
|
FILE_READ_EA, &Obj, &Iosb,
|
|
SHARE_ALL,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
|
|
|
|
RtlFreeUnicodeString(&ParentDir_U);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = NtOpenProcessToken(Process, GENERIC_READ, &TokenHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(DirHandle);
|
|
return Status;
|
|
}
|
|
|
|
SecurityInformation = GROUP_SECURITY_INFORMATION;
|
|
|
|
Status = NtQuerySecurityObject(DirHandle, SecurityInformation,
|
|
NULL, 0, &LengthNeeded);
|
|
|
|
if (STATUS_INVALID_PARAMETER == Status) {
|
|
//
|
|
// Can't get the group from parent dir, use primary group
|
|
// instead.
|
|
//
|
|
Status = NtQueryInformationToken(TokenHandle, TokenPrimaryGroup,
|
|
NULL, 0, &LengthNeeded);
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
|
|
|
|
pGroup = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
|
|
if (NULL == pGroup) {
|
|
NtClose(TokenHandle);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
Status = NtQueryInformationToken(TokenHandle, TokenPrimaryGroup,
|
|
pGroup, LengthNeeded, &LengthNeeded);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
DirGroup = pGroup->PrimaryGroup;
|
|
|
|
} else if (!NT_SUCCESS(Status)) {
|
|
|
|
static int _status;
|
|
|
|
_status = Status;
|
|
|
|
if (STATUS_BUFFER_TOO_SMALL != _status || 0 == LengthNeeded) {
|
|
KdPrint(("PSXSS: NtQSObject returned unexpected %x, %x\n",
|
|
_status, LengthNeeded));
|
|
return _status;
|
|
}
|
|
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == _status);
|
|
|
|
pDirSD = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
|
|
if (NULL == pDirSD) {
|
|
NtClose(DirHandle);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
Status = NtQuerySecurityObject(DirHandle, SecurityInformation,
|
|
pDirSD, LengthNeeded, &Length);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("PSXSS: NtQSD: 0x%x\n", Status));
|
|
KdPrint(("PSXSS: NtQSD: %d vs. %d\n", LengthNeeded, Length));
|
|
return Status;
|
|
}
|
|
|
|
NtClose(DirHandle);
|
|
|
|
Status = RtlGetGroupSecurityDescriptor(pDirSD, &DirGroup,
|
|
&Defaulted);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
}
|
|
|
|
Status = RtlCreateSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = NtQueryInformationToken(TokenHandle, TokenUser, NULL,
|
|
0, &LengthNeeded);
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
|
|
|
|
pSA = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
|
|
if (NULL == pSA) {
|
|
NtClose(TokenHandle);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
Status = NtQueryInformationToken(TokenHandle, TokenUser, pSA,
|
|
LengthNeeded, &LengthNeeded);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("PSXSS: NtQueryInfoToken: 0x%x\n", Status));
|
|
}
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlSetOwnerSecurityDescriptor(pSD, pSA->Sid, FALSE);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
|
|
Status = RtlSetGroupSecurityDescriptor(pSD, DirGroup, FALSE);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
ModeToAccessMask(Mode, &UserAccess, &GroupAccess, &OtherAccess);
|
|
|
|
Status = RtlMakePosixAcl(ACL_REVISION2, pSA->Sid, DirGroup,
|
|
UserAccess, GroupAccess, OtherAccess, 0, NULL, &LengthNeeded);
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
|
|
|
|
pDacl = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
|
|
if (NULL == pDacl) {
|
|
// XXX.mjb: better cleanup needed
|
|
NtClose(TokenHandle);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
Status = RtlMakePosixAcl(ACL_REVISION2, pSA->Sid, DirGroup,
|
|
UserAccess, GroupAccess, OtherAccess, LengthNeeded, pDacl,
|
|
&LengthNeeded);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(pSD,
|
|
TRUE, pDacl, FALSE);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
//
|
|
// The pointers we stick into pvMem will be freed in DeInitSD.
|
|
//
|
|
|
|
i = 0;
|
|
|
|
pvMem[i++] = pDacl;
|
|
pvMem[i++] = pSA;
|
|
if (NULL != pDirSD) {
|
|
pvMem[i++] = pDirSD;
|
|
}
|
|
if (NULL != pGroup) {
|
|
pvMem[i++] = pGroup;
|
|
}
|
|
pvMem[i++] = NULL;
|
|
|
|
NtClose(TokenHandle);
|
|
|
|
ASSERT(RtlValidSecurityDescriptor(pSD));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
// This routine should only be called on SD's initialized with
|
|
// InitSecurityDescriptor(). It frees memory that was allocated
|
|
// there.
|
|
//
|
|
|
|
VOID
|
|
DeInitSecurityDescriptor(
|
|
PSECURITY_DESCRIPTOR pSD,
|
|
PVOID *pvMem
|
|
)
|
|
{
|
|
PACL pDacl;
|
|
NTSTATUS Status;
|
|
BOOLEAN b;
|
|
int i;
|
|
|
|
for (i = 0; NULL != pvMem[i]; ++i)
|
|
RtlFreeHeap(PsxHeap, 0, pvMem[i]);
|
|
|
|
#if 0
|
|
Status = RtlGetDaclSecurityDescriptor(pSD, &b, &pDacl, &b);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
ASSERT(NULL != pDacl);
|
|
|
|
RtlFreeHeap(PsxHeap, 0, pDacl);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
// See if the given group is one that the owner of this process belongs
|
|
// to.
|
|
//
|
|
|
|
static BOOLEAN
|
|
IsUserInGroup(
|
|
PPSX_PROCESS p,
|
|
PSID Group
|
|
)
|
|
{
|
|
HANDLE TokenHandle;
|
|
TOKEN_GROUPS *pGroups;
|
|
ULONG LengthNeeded;
|
|
NTSTATUS Status;
|
|
BOOLEAN RetVal = FALSE;
|
|
ULONG i;
|
|
|
|
Status = NtOpenProcessToken(p->Process, GENERIC_READ, &TokenHandle);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = NtQueryInformationToken(TokenHandle, TokenGroups, NULL,
|
|
0, &LengthNeeded);
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
|
|
|
|
pGroups = RtlAllocateHeap(PsxHeap, 0, LengthNeeded);
|
|
if (NULL == pGroups) {
|
|
NtClose(TokenHandle);
|
|
return FALSE;
|
|
}
|
|
|
|
Status = NtQueryInformationToken(TokenHandle, TokenGroups, pGroups,
|
|
LengthNeeded, &LengthNeeded);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
for (i = 0; i < pGroups->GroupCount; ++i) {
|
|
if (RtlEqualSid(pGroups->Groups[i].Sid, Group)) {
|
|
RetVal = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
RtlFreeHeap(PsxHeap, 0, pGroups);
|
|
NtClose(TokenHandle);
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
|
|
PSID
|
|
GetLoginGroupSid(
|
|
IN PPSX_PROCESS p
|
|
)
|
|
/*++
|
|
|
|
Get the logon group Sid from the supplementary group list. The
|
|
returned Sid is allocated from PsxHeap, and should be freed by
|
|
the caller when he's done with it.
|
|
|
|
Returns NULL upon failure.
|
|
|
|
--*/
|
|
{
|
|
HANDLE TokenHandle;
|
|
NTSTATUS Status;
|
|
PSID NewSid;
|
|
ULONG outlen, i;
|
|
TOKEN_GROUPS *pGroups;
|
|
|
|
Status = NtOpenProcessToken(p->Process, GENERIC_READ,
|
|
&TokenHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return NULL;
|
|
}
|
|
|
|
Status = NtQueryInformationToken(TokenHandle, TokenGroups,
|
|
NULL, 0, &outlen);
|
|
ASSERT(STATUS_BUFFER_TOO_SMALL == Status);
|
|
|
|
pGroups = RtlAllocateHeap(PsxHeap, 0, outlen);
|
|
if (NULL == pGroups) {
|
|
NtClose(TokenHandle);
|
|
return NULL;
|
|
}
|
|
|
|
Status = NtQueryInformationToken(TokenHandle, TokenGroups,
|
|
pGroups, outlen, &outlen);
|
|
if (!NT_SUCCESS(Status)) {
|
|
RtlFreeHeap(PsxHeap, 0, pGroups);
|
|
NtClose(TokenHandle);
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < pGroups->GroupCount; ++i) {
|
|
PSID Sid = pGroups->Groups[i].Sid;
|
|
|
|
if (0xFFF == MakePosixId(Sid)) {
|
|
// This is the login group sid, copy it and return.
|
|
|
|
NewSid = RtlAllocateHeap(PsxHeap, 0,
|
|
RtlLengthSid(Sid));
|
|
if (NULL == NewSid)
|
|
return NULL;
|
|
|
|
Status = RtlCopySid(RtlLengthSid(Sid), NewSid, Sid);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
RtlFreeHeap(PsxHeap, 0, pGroups);
|
|
NtClose(TokenHandle);
|
|
return NewSid;
|
|
}
|
|
}
|
|
RtlFreeHeap(PsxHeap, 0, pGroups);
|
|
NtClose(TokenHandle);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
|
|
ULONG
|
|
OpenTty(
|
|
PPSX_PROCESS p,
|
|
PFILEDESCRIPTOR Fd,
|
|
ULONG DesiredAccess,
|
|
ULONG Flags,
|
|
BOOLEAN NewOpen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to implement an open on the file /dev/tty.
|
|
|
|
Arguments:
|
|
|
|
p - The process on whose behalf the open is performed.
|
|
Fd - The file descriptor to receive the handle.
|
|
DesiredAccess - The access requested on the file.
|
|
Flags -
|
|
NewOpen - FALSE if the file is already open in the console session
|
|
manager. This will be the case for stdin, stdout, and
|
|
stderr. If NewOepn is TRUE, we're opening /dev/tty an
|
|
additional time, and we want the console sess mgr to open
|
|
con: again, to go along.
|
|
|
|
Return Value:
|
|
|
|
A posix error status, or 0 if successful.
|
|
|
|
--*/
|
|
{
|
|
SCREQUESTMSG Request;
|
|
NTSTATUS Status;
|
|
|
|
Fd->SystemOpenFileDesc = AllocateSystemOpenFile();
|
|
if (NULL == Fd->SystemOpenFileDesc) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
if (DesiredAccess & FILE_READ_DATA) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_READ;
|
|
}
|
|
if (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_WRITE;
|
|
}
|
|
|
|
if (Flags & O_NONBLOCK) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_NOBLOCK;
|
|
}
|
|
if (Flags & O_APPEND) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_APPEND;
|
|
}
|
|
|
|
if (ReferenceOrCreateIoNode(PSX_CONSOLE_DEV,
|
|
(ULONG_PTR)p->PsxSession->Terminal->ConsolePort, FALSE,
|
|
&Fd->SystemOpenFileDesc->IoNode)) {
|
|
// null
|
|
} else {
|
|
if (! Fd->SystemOpenFileDesc->IoNode) {
|
|
DeallocateSystemOpenFile(p, Fd->SystemOpenFileDesc);
|
|
return ENOMEM;
|
|
}
|
|
Fd->SystemOpenFileDesc->IoNode->IoVectors = &ConVectors;
|
|
Fd->SystemOpenFileDesc->IoNode->Mode = S_IFCHR | 0700;
|
|
Fd->SystemOpenFileDesc->IoNode->OwnerId = p->EffectiveUid;
|
|
Fd->SystemOpenFileDesc->IoNode->GroupId = p->EffectiveGid;
|
|
}
|
|
RtlLeaveCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
|
|
|
(void)IoOpenNewHandle(p, Fd, NULL);
|
|
|
|
Fd->SystemOpenFileDesc->Terminal = p->PsxSession->Terminal;
|
|
|
|
//
|
|
// Add a reference to the terminal (there is an additional
|
|
// file descriptor open on it).
|
|
//
|
|
|
|
++Fd->SystemOpenFileDesc->Terminal->ReferenceCount;
|
|
|
|
if (!NewOpen) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Send a message to posix.exe, asking him to open the
|
|
// console again.
|
|
//
|
|
|
|
Request.Request = ConRequest;
|
|
Request.d.Con.Request = ScOpenFile;
|
|
|
|
if (DesiredAccess & FILE_WRITE_DATA) {
|
|
Request.d.Con.d.IoBuf.Flags = O_WRONLY;
|
|
} else {
|
|
Request.d.Con.d.IoBuf.Flags = O_RDONLY;
|
|
}
|
|
|
|
PORT_MSG_TOTAL_LENGTH(Request) = sizeof(SCREQUESTMSG);
|
|
PORT_MSG_DATA_LENGTH(Request) = sizeof(SCREQUESTMSG) -
|
|
sizeof(PORT_MESSAGE);
|
|
PORT_MSG_ZERO_INIT(Request) = 0;
|
|
|
|
// XXX.mjb: hold session mgr lock
|
|
|
|
Status = NtRequestWaitReplyPort(p->PsxSession->Terminal->ConsolePort,
|
|
(PPORT_MESSAGE)&Request, (PPORT_MESSAGE)&Request);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrint(("PSXSS: NtRequest: 0x%x\n", Status));
|
|
}
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
// XXX.mjb: release session mgr lock
|
|
|
|
Fd->SystemOpenFileDesc->NtIoHandle = Request.d.Con.d.IoBuf.Handle;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
|
|
ULONG
|
|
OpenDevNull(
|
|
PPSX_PROCESS p,
|
|
PFILEDESCRIPTOR Fd,
|
|
ULONG DesiredAccess,
|
|
ULONG Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to implement an open on the file /dev/null.
|
|
|
|
Arguments:
|
|
|
|
p - The process on whose behalf the open is performed.
|
|
Fd - The file descriptor to receive the handle.
|
|
DesiredAccess - The access requested on the file.
|
|
Flags -
|
|
NewOpen - FALSE if the file is already open in the console session
|
|
manager. This will be the case for stdin, stdout, and
|
|
stderr. If NewOepn is TRUE, we're opening /dev/tty an
|
|
additional time, and we want the console sess mgr to open
|
|
con: again, to go along.
|
|
|
|
|
|
Return Value:
|
|
|
|
A posix error status, or 0 if successful.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Fd->SystemOpenFileDesc = AllocateSystemOpenFile();
|
|
if (NULL == Fd->SystemOpenFileDesc) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
if (DesiredAccess & FILE_READ_DATA) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_READ;
|
|
}
|
|
if (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_WRITE;
|
|
}
|
|
|
|
if (Flags & O_NONBLOCK) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_NOBLOCK;
|
|
}
|
|
if (Flags & O_APPEND) {
|
|
Fd->SystemOpenFileDesc->Flags |= PSX_FD_APPEND;
|
|
}
|
|
|
|
if (ReferenceOrCreateIoNode(PSX_NULL_DEV,
|
|
(ino_t)0, FALSE, &Fd->SystemOpenFileDesc->IoNode)) {
|
|
// null
|
|
} else {
|
|
if (! Fd->SystemOpenFileDesc->IoNode) {
|
|
DeallocateSystemOpenFile(p, Fd->SystemOpenFileDesc);
|
|
return ENOMEM;
|
|
}
|
|
Fd->SystemOpenFileDesc->IoNode->IoVectors = &NullVectors;
|
|
Fd->SystemOpenFileDesc->IoNode->Mode = S_IFCHR | 0666;
|
|
Fd->SystemOpenFileDesc->IoNode->OwnerId = p->EffectiveUid;
|
|
Fd->SystemOpenFileDesc->IoNode->GroupId = p->EffectiveGid;
|
|
}
|
|
RtlLeaveCriticalSection(&Fd->SystemOpenFileDesc->IoNode->IoNodeLock);
|
|
|
|
(void)IoOpenNewHandle(p, Fd, NULL);
|
|
|
|
Fd->SystemOpenFileDesc->Terminal = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
|
|
dev_t
|
|
GetFileDeviceNumber(
|
|
PUNICODE_STRING Path
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Takes a path, like \DosDevices\X:\foo\bar, and returns
|
|
the device number, which in this case is 'X'.
|
|
|
|
Arguments:
|
|
|
|
Path - the path.
|
|
|
|
Return Value:
|
|
|
|
The device number.
|
|
--*/
|
|
{
|
|
wchar_t ch;
|
|
if (NtCurrentPeb()->SessionId) {
|
|
ULONG len;
|
|
PSX_GET_STRLEN(DOSDEVICE_X_A,len);
|
|
ch = Path->Buffer[len-3];
|
|
}else{
|
|
ch = Path->Buffer[12];
|
|
}
|
|
return (dev_t)ch;
|
|
}
|
|
|