Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,286 @@
/**
* WinPR: Windows Portable Runtime
* File Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 bernhard.miklautz@thincast.com
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/config.h>
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/file.h>
#ifdef WINPR_HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "../log.h"
#define TAG WINPR_TAG("file")
#ifndef _WIN32
#ifdef ANDROID
#include <sys/vfs.h>
#else
#include <sys/statvfs.h>
#endif
#include "../handle/handle.h"
#include "../pipe/pipe.h"
#include "namedPipeClient.h"
static BOOL NamedPipeClientIsHandled(HANDLE handle)
{
return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_NAMED_PIPE, TRUE);
}
static BOOL NamedPipeClientCloseHandle(HANDLE handle)
{
WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)handle;
if (!NamedPipeClientIsHandled(handle))
return FALSE;
if (pNamedPipe->clientfd != -1)
{
// WLOG_DBG(TAG, "closing clientfd %d", pNamedPipe->clientfd);
close(pNamedPipe->clientfd);
}
if (pNamedPipe->serverfd != -1)
{
// WLOG_DBG(TAG, "closing serverfd %d", pNamedPipe->serverfd);
close(pNamedPipe->serverfd);
}
if (pNamedPipe->pfnUnrefNamedPipe)
pNamedPipe->pfnUnrefNamedPipe(pNamedPipe);
free(pNamedPipe->lpFileName);
free(pNamedPipe->lpFilePath);
free(pNamedPipe->name);
free(pNamedPipe);
return TRUE;
}
static int NamedPipeClientGetFd(HANDLE handle)
{
WINPR_NAMED_PIPE* file = (WINPR_NAMED_PIPE*)handle;
if (!NamedPipeClientIsHandled(handle))
return -1;
if (file->ServerMode)
return file->serverfd;
else
return file->clientfd;
}
static HANDLE_OPS ops = {
NamedPipeClientIsHandled,
NamedPipeClientCloseHandle,
NamedPipeClientGetFd,
nullptr, /* CleanupHandle */
NamedPipeRead,
nullptr, /* FileReadEx */
nullptr, /* FileReadScatter */
NamedPipeWrite,
nullptr, /* FileWriteEx */
nullptr, /* FileWriteGather */
nullptr, /* FileGetFileSize */
nullptr, /* FlushFileBuffers */
nullptr, /* FileSetEndOfFile */
nullptr, /* FileSetFilePointer */
nullptr, /* SetFilePointerEx */
nullptr, /* FileLockFile */
nullptr, /* FileLockFileEx */
nullptr, /* FileUnlockFile */
nullptr, /* FileUnlockFileEx */
nullptr, /* SetFileTime */
nullptr, /* FileGetFileInformationByHandle */
};
static HANDLE
NamedPipeClientCreateFileA(LPCSTR lpFileName, WINPR_ATTR_UNUSED DWORD dwDesiredAccess,
WINPR_ATTR_UNUSED DWORD dwShareMode,
WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpSecurityAttributes,
WINPR_ATTR_UNUSED DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, WINPR_ATTR_UNUSED HANDLE hTemplateFile)
{
int status = 0;
struct sockaddr_un s = WINPR_C_ARRAY_INIT;
if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
{
WLog_ERR(TAG, "WinPR does not support the FILE_FLAG_OVERLAPPED flag");
SetLastError(ERROR_NOT_SUPPORTED);
return INVALID_HANDLE_VALUE;
}
if (!lpFileName)
return INVALID_HANDLE_VALUE;
if (!IsNamedPipeFileNameA(lpFileName))
return INVALID_HANDLE_VALUE;
WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE));
if (!pNamedPipe)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
}
HANDLE hNamedPipe = (HANDLE)pNamedPipe;
WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ);
pNamedPipe->name = _strdup(lpFileName);
if (!pNamedPipe->name)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto fail;
}
pNamedPipe->dwOpenMode = 0;
pNamedPipe->dwPipeMode = 0;
pNamedPipe->nMaxInstances = 0;
pNamedPipe->nOutBufferSize = 0;
pNamedPipe->nInBufferSize = 0;
pNamedPipe->nDefaultTimeOut = 0;
pNamedPipe->dwFlagsAndAttributes = dwFlagsAndAttributes;
pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName);
if (!pNamedPipe->lpFileName)
goto fail;
pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName);
if (!pNamedPipe->lpFilePath)
goto fail;
pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0);
if (pNamedPipe->clientfd < 0)
goto fail;
pNamedPipe->serverfd = -1;
pNamedPipe->ServerMode = FALSE;
s.sun_family = AF_UNIX;
(void)sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath);
status = connect(pNamedPipe->clientfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un));
pNamedPipe->common.ops = &ops;
if (status != 0)
goto fail;
if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
{
// TODO: Implement
WLog_ERR(TAG, "TODO: implement this");
}
return hNamedPipe;
fail:
if (pNamedPipe)
{
if (pNamedPipe->clientfd >= 0)
close(pNamedPipe->clientfd);
free(pNamedPipe->name);
free(pNamedPipe->lpFileName);
free(pNamedPipe->lpFilePath);
free(pNamedPipe);
}
return INVALID_HANDLE_VALUE;
}
const HANDLE_CREATOR* GetNamedPipeClientHandleCreator(void)
{
static const HANDLE_CREATOR NamedPipeClientHandleCreator = { .IsHandled = IsNamedPipeFileNameA,
.CreateFileA =
NamedPipeClientCreateFileA };
return &NamedPipeClientHandleCreator;
}
#endif
/* Extended API */
#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\"
BOOL IsNamedPipeFileNameA(LPCSTR lpName)
{
return (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) == 0);
}
char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)
{
char* lpFileName = nullptr;
if (!lpName)
return nullptr;
if (!IsNamedPipeFileNameA(lpName))
return nullptr;
lpFileName = _strdup(&lpName[strnlen(NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH))]);
return lpFileName;
}
char* GetNamedPipeUnixDomainSocketBaseFilePathA(void)
{
char* lpTempPath = nullptr;
char* lpPipePath = nullptr;
lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
if (!lpTempPath)
return nullptr;
lpPipePath = GetCombinedPath(lpTempPath, ".pipe");
free(lpTempPath);
return lpPipePath;
}
char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName)
{
char* lpPipePath = nullptr;
char* lpFileName = nullptr;
char* lpFilePath = nullptr;
lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
lpFilePath = GetCombinedPath(lpPipePath, lpFileName);
free(lpPipePath);
free(lpFileName);
return lpFilePath;
}
int GetNamePipeFileDescriptor(HANDLE hNamedPipe)
{
#ifndef _WIN32
int fd = 0;
WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
if (!NamedPipeClientIsHandled(hNamedPipe))
return -1;
fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
return fd;
#else
return -1;
#endif
}