FreeRDP/winpr/libwinpr/file/namedPipeClient.c
Norbert Federa e718fb324b fix race conditions, tests and some invalid return values
Since the current winpr implementation for overlapped operations is
incomplete and buggy, all affected functions will now fail if they are
called with a set FILE_FLAG_OVERLAPPED flag or a non-null pointer to
a OVERLAPPED structure.

winpr/nt:
- use proper one-time initialization on win32
- fix TestNtCreateFile
- fix broken/incomplete _RtlAnsiStringToUnicodeString
- unimplemented functions return appropriate error codes

winpr/pipe:
- improved TestPipeCreateNamedPipe
- rewrite the completely broken TestPipeCreateNamedPipeOverlapped test

rdtk:
- improve test and don't blindly return success

winpr/synch:
- fix race condition in TestSynchTimerQueue

winpr/ssspi:
- fix TestEnumerateSecurityPackages printf output
- fix TestQuerySecurityPackageInfo printf output

winpr/environment:
- fix GetEnvironmentStrings printf output

winpr/comm:
- unimplemented functions return appropriate error codes

winpr/io:
- unimplemented functions return appropriate error codes

winpr/thread:
- implement SwitchToThread() via sched_yield()
2016-06-01 16:26:26 +02:00

310 lines
7.2 KiB
C

/**
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/file.h>
#ifdef 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"
static HANDLE_CREATOR _NamedPipeClientHandleCreator;
static BOOL NamedPipeClientIsHandled(HANDLE handle)
{
WINPR_NAMED_PIPE* pFile = (WINPR_NAMED_PIPE*) handle;
if (!pFile || (pFile->Type != HANDLE_TYPE_NAMED_PIPE) || (pFile == INVALID_HANDLE_VALUE))
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
return TRUE;
}
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,
NULL, /* CleanupHandle */
NamedPipeRead,
NULL, /* FileReadEx */
NULL, /* FileReadScatter */
NamedPipeWrite,
NULL, /* FileWriteEx */
NULL, /* FileWriteGather */
NULL, /* FileGetFileSize */
NULL, /* FlushFileBuffers */
NULL, /* FileSetEndOfFile */
NULL, /* FileSetFilePointer */
NULL, /* SetFilePointerEx */
NULL, /* FileLockFile */
NULL, /* FileLockFileEx */
NULL, /* FileUnlockFile */
NULL, /* FileUnlockFileEx */
NULL /* SetFileTime */
};
static HANDLE NamedPipeClientCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
char* name;
int status;
HANDLE hNamedPipe;
struct sockaddr_un s;
WINPR_NAMED_PIPE* pNamedPipe;
if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
{
WLog_ERR(TAG, "WinPR %s does not support the FILE_FLAG_OVERLAPPED flag", __FUNCTION__);
SetLastError(ERROR_NOT_SUPPORTED);
return INVALID_HANDLE_VALUE;
}
if (!lpFileName)
return INVALID_HANDLE_VALUE;
if (!IsNamedPipeFileNameA(lpFileName))
return INVALID_HANDLE_VALUE;
name = GetNamedPipeNameWithoutPrefixA(lpFileName);
if (!name)
return INVALID_HANDLE_VALUE;
free(name);
pNamedPipe = (WINPR_NAMED_PIPE*) calloc(1, sizeof(WINPR_NAMED_PIPE));
if (!pNamedPipe)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return INVALID_HANDLE_VALUE;
}
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);
free(pNamedPipe);
return INVALID_HANDLE_VALUE;
}
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)
{
free((void *)pNamedPipe->name);
free(pNamedPipe);
return INVALID_HANDLE_VALUE;
}
pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName);
if (!pNamedPipe->lpFilePath)
{
free((void *)pNamedPipe->lpFileName);
free((void *)pNamedPipe->name);
free(pNamedPipe);
return INVALID_HANDLE_VALUE;
}
pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0);
pNamedPipe->serverfd = -1;
pNamedPipe->ServerMode = FALSE;
ZeroMemory(&s, sizeof(struct sockaddr_un));
s.sun_family = AF_UNIX;
strcpy(s.sun_path, pNamedPipe->lpFilePath);
status = connect(pNamedPipe->clientfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un));
pNamedPipe->ops = &ops;
if (status != 0)
{
close(pNamedPipe->clientfd);
free((char*) pNamedPipe->name);
free((char*) pNamedPipe->lpFileName);
free((char*) pNamedPipe->lpFilePath);
free(pNamedPipe);
return INVALID_HANDLE_VALUE;
}
if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
{
#if 0
int flags = fcntl(pNamedPipe->clientfd, F_GETFL);
if (flags != -1)
fcntl(pNamedPipe->clientfd, F_SETFL, flags | O_NONBLOCK);
#endif
}
return hNamedPipe;
}
HANDLE_CREATOR *GetNamedPipeClientHandleCreator(void)
{
_NamedPipeClientHandleCreator.IsHandled = IsNamedPipeFileNameA;
_NamedPipeClientHandleCreator.CreateFileA = NamedPipeClientCreateFileA;
return &_NamedPipeClientHandleCreator;
}
#endif
/* Extended API */
#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\"
BOOL IsNamedPipeFileNameA(LPCSTR lpName)
{
if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0)
return FALSE;
return TRUE;
}
char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)
{
char* lpFileName;
if (!lpName)
return NULL;
if (!IsNamedPipeFileNameA(lpName))
return NULL;
lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]);
return lpFileName;
}
char* GetNamedPipeUnixDomainSocketBaseFilePathA()
{
char* lpTempPath;
char* lpPipePath;
lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
if (!lpTempPath)
return NULL;
lpPipePath = GetCombinedPath(lpTempPath, ".pipe");
free(lpTempPath);
return lpPipePath;
}
char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName)
{
char* lpPipePath;
char* lpFileName;
char* lpFilePath;
lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
lpFilePath = GetCombinedPath(lpPipePath, (char*) lpFileName);
free(lpPipePath);
free(lpFileName);
return lpFilePath;
}
int GetNamePipeFileDescriptor(HANDLE hNamedPipe)
{
#ifndef _WIN32
int fd;
WINPR_NAMED_PIPE* pNamedPipe;
pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe;
if (!pNamedPipe || pNamedPipe->Type != HANDLE_TYPE_NAMED_PIPE)
return -1;
fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
return fd;
#else
return -1;
#endif
}