Coverage Report

Created: 2026-08-31 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/winpr/libwinpr/file/namedPipeClient.c
Line
Count
Source
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
    pNamedPipe->clientfd = -1;
65
0
  }
66
67
0
  if (pNamedPipe->serverfd != -1)
68
0
  {
69
    // WLOG_DBG(TAG, "closing serverfd %d", pNamedPipe->serverfd);
70
0
    close(pNamedPipe->serverfd);
71
0
    pNamedPipe->serverfd = -1;
72
0
  }
73
74
0
  if (pNamedPipe->pfnUnrefNamedPipe)
75
0
    pNamedPipe->pfnUnrefNamedPipe(pNamedPipe);
76
77
0
  free(pNamedPipe->lpFileName);
78
0
  pNamedPipe->lpFileName = nullptr;
79
0
  free(pNamedPipe->lpFilePath);
80
0
  pNamedPipe->lpFilePath = nullptr;
81
0
  free(pNamedPipe->name);
82
0
  pNamedPipe->name = nullptr;
83
0
  return TRUE;
84
0
}
85
86
static int NamedPipeClientGetFd(HANDLE handle)
87
0
{
88
0
  WINPR_NAMED_PIPE* file = (WINPR_NAMED_PIPE*)handle;
89
90
0
  if (!NamedPipeClientIsHandled(handle))
91
0
    return -1;
92
93
0
  if (file->ServerMode)
94
0
    return file->serverfd;
95
0
  else
96
0
    return file->clientfd;
97
0
}
98
99
static HANDLE_OPS ops = {
100
  NamedPipeClientIsHandled,
101
  NamedPipeClientCloseHandle,
102
  NamedPipeClientGetFd,
103
  nullptr, /* CleanupHandle */
104
  NamedPipeRead,
105
  nullptr, /* FileReadEx */
106
  nullptr, /* FileReadScatter */
107
  NamedPipeWrite,
108
  nullptr, /* FileWriteEx */
109
  nullptr, /* FileWriteGather */
110
  nullptr, /* FileGetFileSize */
111
  nullptr, /*  FlushFileBuffers */
112
  nullptr, /* FileSetEndOfFile */
113
  nullptr, /* FileSetFilePointer */
114
  nullptr, /* SetFilePointerEx */
115
  nullptr, /* FileLockFile */
116
  nullptr, /* FileLockFileEx */
117
  nullptr, /* FileUnlockFile */
118
  nullptr, /* FileUnlockFileEx */
119
  nullptr, /* SetFileTime */
120
  nullptr, /* FileGetFileInformationByHandle */
121
};
122
123
WINPR_ATTR_NODISCARD
124
static HANDLE NamedPipeClientCreateFileA(LPCSTR lpFileName, WINPR_ATTR_UNUSED DWORD dwDesiredAccess,
125
                                         WINPR_ATTR_UNUSED DWORD dwShareMode,
126
                                         LPSECURITY_ATTRIBUTES lpSecurityAttributes,
127
                                         WINPR_ATTR_UNUSED DWORD dwCreationDisposition,
128
                                         DWORD dwFlagsAndAttributes,
129
                                         WINPR_ATTR_UNUSED HANDLE hTemplateFile)
130
0
{
131
0
  int status = 0;
132
0
  struct sockaddr_un s = WINPR_C_ARRAY_INIT;
133
134
0
  if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
135
0
  {
136
0
    WLog_ERR(TAG, "WinPR does not support the FILE_FLAG_OVERLAPPED flag");
137
0
    SetLastError(ERROR_NOT_SUPPORTED);
138
0
    return INVALID_HANDLE_VALUE;
139
0
  }
140
141
0
  if (!lpFileName)
142
0
    return INVALID_HANDLE_VALUE;
143
144
0
  if (!IsNamedPipeFileNameA(lpFileName))
145
0
    return INVALID_HANDLE_VALUE;
146
147
0
  WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE));
148
149
0
  if (!pNamedPipe)
150
0
  {
151
0
    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
152
0
    return INVALID_HANDLE_VALUE;
153
0
  }
154
155
0
  HANDLE hNamedPipe = (HANDLE)pNamedPipe;
156
0
  WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ);
157
0
  pNamedPipe->name = _strdup(lpFileName);
158
159
0
  if (!pNamedPipe->name)
160
0
  {
161
0
    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
162
0
    goto fail;
163
0
  }
164
165
0
  pNamedPipe->dwOpenMode = 0;
166
0
  pNamedPipe->dwPipeMode = 0;
167
0
  pNamedPipe->nMaxInstances = 0;
168
0
  pNamedPipe->nOutBufferSize = 0;
169
0
  pNamedPipe->nInBufferSize = 0;
170
0
  pNamedPipe->nDefaultTimeOut = 0;
171
0
  pNamedPipe->dwFlagsAndAttributes = dwFlagsAndAttributes;
172
0
  pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName);
173
174
0
  if (!pNamedPipe->lpFileName)
175
0
    goto fail;
176
177
0
  pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName);
178
179
0
  if (!pNamedPipe->lpFilePath)
180
0
    goto fail;
181
182
0
  pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0);
183
0
  if (pNamedPipe->clientfd < 0)
184
0
    goto fail;
185
186
0
  {
187
0
    const BOOL inherit = lpSecurityAttributes && lpSecurityAttributes->bInheritHandle;
188
0
    if (!winpr_set_cloexec(pNamedPipe->clientfd, !inherit))
189
0
      goto fail;
190
0
  }
191
192
0
  pNamedPipe->serverfd = -1;
193
0
  pNamedPipe->ServerMode = FALSE;
194
0
  s.sun_family = AF_UNIX;
195
0
  (void)sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath);
196
0
  status = connect(pNamedPipe->clientfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un));
197
0
  pNamedPipe->common.ops = &ops;
198
199
0
  if (status != 0)
200
0
    goto fail;
201
202
0
  if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
203
0
  {
204
    // TODO: Implement
205
0
    WLog_ERR(TAG, "TODO: implement this");
206
0
  }
207
208
0
  return hNamedPipe;
209
210
0
fail:
211
0
  if (pNamedPipe)
212
0
  {
213
0
    if (pNamedPipe->clientfd >= 0)
214
0
      close(pNamedPipe->clientfd);
215
0
    free(pNamedPipe->name);
216
0
    free(pNamedPipe->lpFileName);
217
0
    free(pNamedPipe->lpFilePath);
218
0
    free(pNamedPipe);
219
0
  }
220
0
  return INVALID_HANDLE_VALUE;
221
0
}
222
223
const HANDLE_CREATOR* GetNamedPipeClientHandleCreator(void)
224
0
{
225
0
  static const HANDLE_CREATOR NamedPipeClientHandleCreator = { .IsHandled = IsNamedPipeFileNameA,
226
0
                                                             .CreateFileA =
227
0
                                                                 NamedPipeClientCreateFileA };
228
0
  return &NamedPipeClientHandleCreator;
229
0
}
230
231
#endif
232
233
/* Extended API */
234
235
0
#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\"
236
237
BOOL IsNamedPipeFileNameA(LPCSTR lpName)
238
0
{
239
0
  return (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) == 0);
240
0
}
241
242
char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)
243
0
{
244
0
  char* lpFileName = nullptr;
245
246
0
  if (!lpName)
247
0
    return nullptr;
248
249
0
  if (!IsNamedPipeFileNameA(lpName))
250
0
    return nullptr;
251
252
0
  lpFileName = _strdup(&lpName[strnlen(NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH))]);
253
0
  return lpFileName;
254
0
}
255
256
char* GetNamedPipeUnixDomainSocketBaseFilePathA(void)
257
0
{
258
0
  char* lpTempPath = nullptr;
259
0
  char* lpPipePath = nullptr;
260
0
  lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
261
262
0
  if (!lpTempPath)
263
0
    return nullptr;
264
265
0
  lpPipePath = GetCombinedPath(lpTempPath, ".pipe");
266
0
  free(lpTempPath);
267
0
  return lpPipePath;
268
0
}
269
270
char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName)
271
0
{
272
0
  char* lpPipePath = nullptr;
273
0
  char* lpFileName = nullptr;
274
0
  char* lpFilePath = nullptr;
275
0
  lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
276
0
  lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
277
0
  lpFilePath = GetCombinedPath(lpPipePath, lpFileName);
278
0
  free(lpPipePath);
279
0
  free(lpFileName);
280
0
  return lpFilePath;
281
0
}
282
283
int GetNamePipeFileDescriptor(HANDLE hNamedPipe)
284
0
{
285
0
#ifndef _WIN32
286
0
  int fd = 0;
287
0
  WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
288
289
0
  if (!NamedPipeClientIsHandled(hNamedPipe))
290
0
    return -1;
291
292
0
  fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
293
0
  return fd;
294
#else
295
  return -1;
296
#endif
297
0
}