FreeRDP
namedPipeClient.c
1 
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 {
50  return WINPR_HANDLE_IS_HANDLED(handle, HANDLE_TYPE_NAMED_PIPE, TRUE);
51 }
52 
53 static BOOL NamedPipeClientCloseHandle(HANDLE handle)
54 {
55  WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)handle;
56 
57  if (!NamedPipeClientIsHandled(handle))
58  return FALSE;
59 
60  if (pNamedPipe->clientfd != -1)
61  {
62  // WLOG_DBG(TAG, "closing clientfd %d", pNamedPipe->clientfd);
63  close(pNamedPipe->clientfd);
64  }
65 
66  if (pNamedPipe->serverfd != -1)
67  {
68  // WLOG_DBG(TAG, "closing serverfd %d", pNamedPipe->serverfd);
69  close(pNamedPipe->serverfd);
70  }
71 
72  if (pNamedPipe->pfnUnrefNamedPipe)
73  pNamedPipe->pfnUnrefNamedPipe(pNamedPipe);
74 
75  free(pNamedPipe->lpFileName);
76  free(pNamedPipe->lpFilePath);
77  free(pNamedPipe->name);
78  free(pNamedPipe);
79  return TRUE;
80 }
81 
82 static int NamedPipeClientGetFd(HANDLE handle)
83 {
84  WINPR_NAMED_PIPE* file = (WINPR_NAMED_PIPE*)handle;
85 
86  if (!NamedPipeClientIsHandled(handle))
87  return -1;
88 
89  if (file->ServerMode)
90  return file->serverfd;
91  else
92  return file->clientfd;
93 }
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 NamedPipeClientCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess,
120  DWORD dwShareMode,
121  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
122  DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
123  HANDLE hTemplateFile)
124 {
125  int status = 0;
126  struct sockaddr_un s = { 0 };
127 
128  if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
129  {
130  WLog_ERR(TAG, "WinPR does not support the FILE_FLAG_OVERLAPPED flag");
131  SetLastError(ERROR_NOT_SUPPORTED);
132  return INVALID_HANDLE_VALUE;
133  }
134 
135  if (!lpFileName)
136  return INVALID_HANDLE_VALUE;
137 
138  if (!IsNamedPipeFileNameA(lpFileName))
139  return INVALID_HANDLE_VALUE;
140 
141  WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE));
142 
143  if (!pNamedPipe)
144  {
145  SetLastError(ERROR_NOT_ENOUGH_MEMORY);
146  return INVALID_HANDLE_VALUE;
147  }
148 
149  HANDLE hNamedPipe = (HANDLE)pNamedPipe;
150  WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ);
151  pNamedPipe->name = _strdup(lpFileName);
152 
153  if (!pNamedPipe->name)
154  {
155  SetLastError(ERROR_NOT_ENOUGH_MEMORY);
156  goto fail;
157  }
158 
159  pNamedPipe->dwOpenMode = 0;
160  pNamedPipe->dwPipeMode = 0;
161  pNamedPipe->nMaxInstances = 0;
162  pNamedPipe->nOutBufferSize = 0;
163  pNamedPipe->nInBufferSize = 0;
164  pNamedPipe->nDefaultTimeOut = 0;
165  pNamedPipe->dwFlagsAndAttributes = dwFlagsAndAttributes;
166  pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName);
167 
168  if (!pNamedPipe->lpFileName)
169  goto fail;
170 
171  pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName);
172 
173  if (!pNamedPipe->lpFilePath)
174  goto fail;
175 
176  pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0);
177  if (pNamedPipe->clientfd < 0)
178  goto fail;
179 
180  pNamedPipe->serverfd = -1;
181  pNamedPipe->ServerMode = FALSE;
182  s.sun_family = AF_UNIX;
183  (void)sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath);
184  status = connect(pNamedPipe->clientfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un));
185  pNamedPipe->common.ops = &ops;
186 
187  if (status != 0)
188  goto fail;
189 
190  if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)
191  {
192 #if 0
193  int flags = fcntl(pNamedPipe->clientfd, F_GETFL);
194 
195  if (flags != -1)
196  (void)fcntl(pNamedPipe->clientfd, F_SETFL, flags | O_NONBLOCK);
197 
198 #endif
199  }
200 
201  return hNamedPipe;
202 
203 fail:
204  if (pNamedPipe)
205  {
206  if (pNamedPipe->clientfd >= 0)
207  close(pNamedPipe->clientfd);
208  free(pNamedPipe->name);
209  free(pNamedPipe->lpFileName);
210  free(pNamedPipe->lpFilePath);
211  free(pNamedPipe);
212  }
213  return INVALID_HANDLE_VALUE;
214 }
215 
216 const HANDLE_CREATOR* GetNamedPipeClientHandleCreator(void)
217 {
218  static const HANDLE_CREATOR NamedPipeClientHandleCreator = { .IsHandled = IsNamedPipeFileNameA,
219  .CreateFileA =
220  NamedPipeClientCreateFileA };
221  return &NamedPipeClientHandleCreator;
222 }
223 
224 #endif
225 
226 /* Extended API */
227 
228 #define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\"
229 
230 BOOL IsNamedPipeFileNameA(LPCSTR lpName)
231 {
232  if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0)
233  return FALSE;
234 
235  return TRUE;
236 }
237 
238 char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)
239 {
240  char* lpFileName = NULL;
241 
242  if (!lpName)
243  return NULL;
244 
245  if (!IsNamedPipeFileNameA(lpName))
246  return NULL;
247 
248  lpFileName = _strdup(&lpName[strnlen(NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH))]);
249  return lpFileName;
250 }
251 
252 char* GetNamedPipeUnixDomainSocketBaseFilePathA(void)
253 {
254  char* lpTempPath = NULL;
255  char* lpPipePath = NULL;
256  lpTempPath = GetKnownPath(KNOWN_PATH_TEMP);
257 
258  if (!lpTempPath)
259  return NULL;
260 
261  lpPipePath = GetCombinedPath(lpTempPath, ".pipe");
262  free(lpTempPath);
263  return lpPipePath;
264 }
265 
266 char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName)
267 {
268  char* lpPipePath = NULL;
269  char* lpFileName = NULL;
270  char* lpFilePath = NULL;
271  lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA();
272  lpFileName = GetNamedPipeNameWithoutPrefixA(lpName);
273  lpFilePath = GetCombinedPath(lpPipePath, lpFileName);
274  free(lpPipePath);
275  free(lpFileName);
276  return lpFilePath;
277 }
278 
279 int GetNamePipeFileDescriptor(HANDLE hNamedPipe)
280 {
281 #ifndef _WIN32
282  int fd = 0;
283  WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
284 
285  if (!NamedPipeClientIsHandled(hNamedPipe))
286  return -1;
287 
288  fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
289  return fd;
290 #else
291  return -1;
292 #endif
293 }