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