Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/winpr/libwinpr/file/namedPipeClient.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * File Functions
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2014 Hewlett-Packard Development Company, L.P.
7
 * Copyright 2015 Thincast Technologies GmbH
8
 * Copyright 2015 bernhard.miklautz@thincast.com
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <winpr/config.h>
23
24
#include <winpr/crt.h>
25
#include <winpr/path.h>
26
#include <winpr/file.h>
27
28
#ifdef WINPR_HAVE_UNISTD_H
29
#include <unistd.h>
30
#endif
31
32
#include "../log.h"
33
#define TAG WINPR_TAG("file")
34
35
#ifndef _WIN32
36
37
#ifdef ANDROID
38
#include <sys/vfs.h>
39
#else
40
#include <sys/statvfs.h>
41
#endif
42
43
#include "../handle/handle.h"
44
45
#include "../pipe/pipe.h"
46
#include "namedPipeClient.h"
47
48
static BOOL NamedPipeClientIsHandled(HANDLE handle)
49
0
{
50
0
  return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_NAMED_PIPE, TRUE);
51
0
}
52
53
static BOOL NamedPipeClientCloseHandle(HANDLE handle)
54
0
{
55
0
  WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)handle;
56
57
0
  if (!NamedPipeClientIsHandled(handle))
58
0
    return FALSE;
59
60
0
  if (pNamedPipe->clientfd != -1)
61
0
  {
62
    // WLOG_DBG(TAG, "closing clientfd %d", pNamedPipe->clientfd);
63
0
    close(pNamedPipe->clientfd);
64
0
  }
65
66
0
  if (pNamedPipe->serverfd != -1)
67
0
  {
68
    // WLOG_DBG(TAG, "closing serverfd %d", pNamedPipe->serverfd);
69
0
    close(pNamedPipe->serverfd);
70
0
  }
71
72
0
  if (pNamedPipe->pfnUnrefNamedPipe)
73
0
    pNamedPipe->pfnUnrefNamedPipe(pNamedPipe);
74
75
0
  free(pNamedPipe->lpFileName);
76
0
  free(pNamedPipe->lpFilePath);
77
0
  free(pNamedPipe->name);
78
0
  free(pNamedPipe);
79
0
  return TRUE;
80
0
}
81
82
static int NamedPipeClientGetFd(HANDLE handle)
83
0
{
84
0
  WINPR_NAMED_PIPE* file = (WINPR_NAMED_PIPE*)handle;
85
86
0
  if (!NamedPipeClientIsHandled(handle))
87
0
    return -1;
88
89
0
  if (file->ServerMode)
90
0
    return file->serverfd;
91
0
  else
92
0
    return file->clientfd;
93
0
}
94
95
static HANDLE_OPS ops = {
96
  NamedPipeClientIsHandled,
97
  NamedPipeClientCloseHandle,
98
  NamedPipeClientGetFd,
99
  NULL, /* CleanupHandle */
100
  NamedPipeRead,
101
  NULL, /* FileReadEx */
102
  NULL, /* FileReadScatter */
103
  NamedPipeWrite,
104
  NULL, /* FileWriteEx */
105
  NULL, /* FileWriteGather */
106
  NULL, /* FileGetFileSize */
107
  NULL, /*  FlushFileBuffers */
108
  NULL, /* FileSetEndOfFile */
109
  NULL, /* FileSetFilePointer */
110
  NULL, /* SetFilePointerEx */
111
  NULL, /* FileLockFile */
112
  NULL, /* FileLockFileEx */
113
  NULL, /* FileUnlockFile */
114
  NULL, /* FileUnlockFileEx */
115
  NULL, /* SetFileTime */
116
  NULL, /* FileGetFileInformationByHandle */
117
};
118
119
static HANDLE
120
NamedPipeClientCreateFileA(LPCSTR lpFileName, WINPR_ATTR_UNUSED DWORD dwDesiredAccess,
121
                           WINPR_ATTR_UNUSED DWORD dwShareMode,
122
                           WINPR_ATTR_UNUSED LPSECURITY_ATTRIBUTES lpSecurityAttributes,
123
                           WINPR_ATTR_UNUSED DWORD dwCreationDisposition,
124
                           DWORD dwFlagsAndAttributes, WINPR_ATTR_UNUSED HANDLE hTemplateFile)
125
0
{
126
0
  int status = 0;
127
0
  struct sockaddr_un s = { 0 };
128
129
0
  if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
130
0
  {
131
0
    WLog_ERR(TAG, "WinPR does not support the FILE_FLAG_OVERLAPPED flag");
132
0
    SetLastError(ERROR_NOT_SUPPORTED);
133
0
    return INVALID_HANDLE_VALUE;
134
0
  }
135
136
0
  if (!lpFileName)
137
0
    return INVALID_HANDLE_VALUE;
138
139
0
  if (!IsNamedPipeFileNameA(lpFileName))
140
0
    return INVALID_HANDLE_VALUE;
141
142
0
  WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE));
143
144
0
  if (!pNamedPipe)
145
0
  {
146
0
    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
147
0
    return INVALID_HANDLE_VALUE;
148
0
  }
149
150
0
  HANDLE hNamedPipe = (HANDLE)pNamedPipe;
151
0
  WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ);
152
0
  pNamedPipe->name = _strdup(lpFileName);
153
154
0
  if (!pNamedPipe->name)
155
0
  {
156
0
    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
157
0
    goto fail;
158
0
  }
159
160
0
  pNamedPipe->dwOpenMode = 0;
161
0
  pNamedPipe->dwPipeMode = 0;
162
0
  pNamedPipe->nMaxInstances = 0;
163
0
  pNamedPipe->nOutBufferSize = 0;
164
0
  pNamedPipe->nInBufferSize = 0;
165
0
  pNamedPipe->nDefaultTimeOut = 0;
166
0
  pNamedPipe->dwFlagsAndAttributes = dwFlagsAndAttributes;
167
0
  pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName);
168
169
0
  if (!pNamedPipe->lpFileName)
170
0
    goto fail;
171
172
0
  pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName);
173
174
0
  if (!pNamedPipe->lpFilePath)
175
0
    goto fail;
176
177
0
  pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0);
178
0
  if (pNamedPipe->clientfd < 0)
179
0
    goto fail;
180
181
0
  pNamedPipe->serverfd = -1;
182
0
  pNamedPipe->ServerMode = FALSE;
183
0
  s.sun_family = AF_UNIX;
184
0
  (void)sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath);
185
0
  status = connect(pNamedPipe->clientfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un));
186
0
  pNamedPipe->common.ops = &ops;
187
188
0
  if (status != 0)
189
0
    goto fail;
190
191
0
  if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
192
0
  {
193
    // TODO: Implement
194
0
    WLog_ERR(TAG, "TODO: implement this");
195
0
  }
196
197
0
  return hNamedPipe;
198
199
0
fail:
200
0
  if (pNamedPipe)
201
0
  {
202
0
    if (pNamedPipe->clientfd >= 0)
203
0
      close(pNamedPipe->clientfd);
204
0
    free(pNamedPipe->name);
205
0
    free(pNamedPipe->lpFileName);
206
0
    free(pNamedPipe->lpFilePath);
207
0
    free(pNamedPipe);
208
0
  }
209
0
  return INVALID_HANDLE_VALUE;
210
0
}
211
212
const HANDLE_CREATOR* GetNamedPipeClientHandleCreator(void)
213
0
{
214
0
  static const HANDLE_CREATOR NamedPipeClientHandleCreator = { .IsHandled = IsNamedPipeFileNameA,
215
0
                                                             .CreateFileA =
216
0
                                                                 NamedPipeClientCreateFileA };
217
0
  return &NamedPipeClientHandleCreator;
218
0
}
219
220
#endif
221
222
/* Extended API */
223
224
0
#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\"
225
226
BOOL IsNamedPipeFileNameA(LPCSTR lpName)
227
0
{
228
0
  if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0)
229
0
    return FALSE;
230
231
0
  return TRUE;
232
0
}
233
234
char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)
235
0
{
236
0
  char* lpFileName = NULL;
237
238
0
  if (!lpName)
239
0
    return NULL;
240
241
0
  if (!IsNamedPipeFileNameA(lpName))
242
0
    return NULL;
243
244
0
  lpFileName = _strdup(&lpName[strnlen(NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH))]);
245
0
  return lpFileName;
246
0
}
247
248
char* GetNamedPipeUnixDomainSocketBaseFilePathA(void)
249
0
{
250
0
  char* lpTempPath = NULL;
251
0
  char* lpPipePath = NULL;
252
0
  lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
253
254
0
  if (!lpTempPath)
255
0
    return NULL;
256
257
0
  lpPipePath = GetCombinedPath(lpTempPath, ".pipe");
258
0
  free(lpTempPath);
259
0
  return lpPipePath;
260
0
}
261
262
char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName)
263
0
{
264
0
  char* lpPipePath = NULL;
265
0
  char* lpFileName = NULL;
266
0
  char* lpFilePath = NULL;
267
0
  lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
268
0
  lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
269
0
  lpFilePath = GetCombinedPath(lpPipePath, lpFileName);
270
0
  free(lpPipePath);
271
0
  free(lpFileName);
272
0
  return lpFilePath;
273
0
}
274
275
int GetNamePipeFileDescriptor(HANDLE hNamedPipe)
276
0
{
277
0
#ifndef _WIN32
278
0
  int fd = 0;
279
0
  WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
280
281
0
  if (!NamedPipeClientIsHandled(hNamedPipe))
282
0
    return -1;
283
284
0
  fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
285
0
  return fd;
286
#else
287
  return -1;
288
#endif
289
0
}