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