1 /**
2  * WinPR: Windows Portable Runtime
3  * Pipe Functions
4  *
5  * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  * Copyright 2017 Armin Novak <armin.novak@thincast.com>
7  * Copyright 2017 Thincast Technologies GmbH
8  *
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/synch.h>
29 #include <winpr/handle.h>
30 
31 #include <winpr/pipe.h>
32 
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 
37 #ifndef _WIN32
38 
39 #include "../handle/handle.h"
40 
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <sys/un.h>
44 #include <sys/socket.h>
45 #include <assert.h>
46 #include <unistd.h>
47 
48 #ifdef HAVE_SYS_AIO_H
49 #undef HAVE_SYS_AIO_H /* disable for now, incomplete */
50 #endif
51 
52 #ifdef HAVE_SYS_AIO_H
53 #include <aio.h>
54 #endif
55 
56 #include "pipe.h"
57 
58 #include "../log.h"
59 #define TAG WINPR_TAG("pipe")
60 
61 /*
62  * Since the WinPR implementation of named pipes makes use of UNIX domain
63  * sockets, it is not possible to bind the same name more than once (i.e.,
64  * SO_REUSEADDR does not work with UNIX domain sockets).  As a result, the
65  * first call to CreateNamedPipe with name n creates a "shared" UNIX domain
66  * socket descriptor that gets duplicated via dup() for the first and all
67  * subsequent calls to CreateNamedPipe with name n.
68  *
69  * The following array keeps track of the references to the shared socked
70  * descriptors. If an entry's reference count is zero the base socket
71  * descriptor gets closed and the entry is removed from the list.
72  */
73 
74 static wArrayList* g_NamedPipeServerSockets = NULL;
75 
76 typedef struct _NamedPipeServerSocketEntry
77 {
78 	char* name;
79 	int serverfd;
80 	int references;
81 } NamedPipeServerSocketEntry;
82 
PipeIsHandled(HANDLE handle)83 static BOOL PipeIsHandled(HANDLE handle)
84 {
85 	WINPR_PIPE* pPipe = (WINPR_PIPE*)handle;
86 
87 	if (!pPipe || (pPipe->Type != HANDLE_TYPE_ANONYMOUS_PIPE))
88 	{
89 		SetLastError(ERROR_INVALID_HANDLE);
90 		return FALSE;
91 	}
92 
93 	return TRUE;
94 }
95 
PipeGetFd(HANDLE handle)96 static int PipeGetFd(HANDLE handle)
97 {
98 	WINPR_PIPE* pipe = (WINPR_PIPE*)handle;
99 
100 	if (!PipeIsHandled(handle))
101 		return -1;
102 
103 	return pipe->fd;
104 }
105 
PipeCloseHandle(HANDLE handle)106 static BOOL PipeCloseHandle(HANDLE handle)
107 {
108 	WINPR_PIPE* pipe = (WINPR_PIPE*)handle;
109 
110 	if (!PipeIsHandled(handle))
111 		return FALSE;
112 
113 	if (pipe->fd != -1)
114 	{
115 		close(pipe->fd);
116 		pipe->fd = -1;
117 	}
118 
119 	free(handle);
120 	return TRUE;
121 }
122 
PipeRead(PVOID Object,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)123 static BOOL PipeRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
124                      LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
125 {
126 	int io_status;
127 	WINPR_PIPE* pipe;
128 	BOOL status = TRUE;
129 
130 	if (lpOverlapped)
131 	{
132 		WLog_ERR(TAG, "WinPR %s does not support the lpOverlapped parameter", __FUNCTION__);
133 		SetLastError(ERROR_NOT_SUPPORTED);
134 		return FALSE;
135 	}
136 
137 	pipe = (WINPR_PIPE*)Object;
138 
139 	do
140 	{
141 		io_status = read(pipe->fd, lpBuffer, nNumberOfBytesToRead);
142 	} while ((io_status < 0) && (errno == EINTR));
143 
144 	if (io_status < 0)
145 	{
146 		status = FALSE;
147 
148 		switch (errno)
149 		{
150 			case EWOULDBLOCK:
151 				SetLastError(ERROR_NO_DATA);
152 				break;
153 		}
154 	}
155 
156 	if (lpNumberOfBytesRead)
157 		*lpNumberOfBytesRead = io_status;
158 
159 	return status;
160 }
161 
PipeWrite(PVOID Object,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped)162 static BOOL PipeWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
163                       LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
164 {
165 	int io_status;
166 	WINPR_PIPE* pipe;
167 
168 	if (lpOverlapped)
169 	{
170 		WLog_ERR(TAG, "WinPR %s does not support the lpOverlapped parameter", __FUNCTION__);
171 		SetLastError(ERROR_NOT_SUPPORTED);
172 		return FALSE;
173 	}
174 
175 	pipe = (WINPR_PIPE*)Object;
176 
177 	do
178 	{
179 		io_status = write(pipe->fd, lpBuffer, nNumberOfBytesToWrite);
180 	} while ((io_status < 0) && (errno == EINTR));
181 
182 	if ((io_status < 0) && (errno == EWOULDBLOCK))
183 		io_status = 0;
184 
185 	*lpNumberOfBytesWritten = io_status;
186 	return TRUE;
187 }
188 
189 static HANDLE_OPS ops = {
190 	PipeIsHandled, PipeCloseHandle,
191 	PipeGetFd,     NULL, /* CleanupHandle */
192 	PipeRead,      NULL, /* FileReadEx */
193 	NULL,                /* FileReadScatter */
194 	PipeWrite,     NULL, /* FileWriteEx */
195 	NULL,                /* FileWriteGather */
196 	NULL,                /* FileGetFileSize */
197 	NULL,                /*  FlushFileBuffers */
198 	NULL,                /* FileSetEndOfFile */
199 	NULL,                /* FileSetFilePointer */
200 	NULL,                /* SetFilePointerEx */
201 	NULL,                /* FileLockFile */
202 	NULL,                /* FileLockFileEx */
203 	NULL,                /* FileUnlockFile */
204 	NULL,                /* FileUnlockFileEx */
205 	NULL                 /* SetFileTime */
206 };
207 
NamedPipeIsHandled(HANDLE handle)208 static BOOL NamedPipeIsHandled(HANDLE handle)
209 {
210 	WINPR_NAMED_PIPE* pPipe = (WINPR_NAMED_PIPE*)handle;
211 
212 	if (!pPipe || (pPipe->Type != HANDLE_TYPE_NAMED_PIPE) || (pPipe == INVALID_HANDLE_VALUE))
213 	{
214 		SetLastError(ERROR_INVALID_HANDLE);
215 		return FALSE;
216 	}
217 
218 	return TRUE;
219 }
220 
NamedPipeGetFd(HANDLE handle)221 static int NamedPipeGetFd(HANDLE handle)
222 {
223 	WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*)handle;
224 
225 	if (!NamedPipeIsHandled(handle))
226 		return -1;
227 
228 	if (pipe->ServerMode)
229 		return pipe->serverfd;
230 
231 	return pipe->clientfd;
232 }
233 
NamedPipeCloseHandle(HANDLE handle)234 static BOOL NamedPipeCloseHandle(HANDLE handle)
235 {
236 	WINPR_NAMED_PIPE* pNamedPipe = (WINPR_NAMED_PIPE*)handle;
237 
238 	/* This check confuses the analyzer. Since not all handle
239 	 * types are handled here, it guesses that the memory of a
240 	 * NamedPipeHandle may leak. */
241 #ifndef __clang_analyzer__
242 	if (!NamedPipeIsHandled(handle))
243 		return FALSE;
244 #endif
245 
246 	if (pNamedPipe->pfnUnrefNamedPipe)
247 		pNamedPipe->pfnUnrefNamedPipe(pNamedPipe);
248 
249 	free(pNamedPipe->name);
250 	free(pNamedPipe->lpFileName);
251 	free(pNamedPipe->lpFilePath);
252 
253 	if (pNamedPipe->serverfd != -1)
254 		close(pNamedPipe->serverfd);
255 
256 	if (pNamedPipe->clientfd != -1)
257 		close(pNamedPipe->clientfd);
258 
259 	free(pNamedPipe);
260 	return TRUE;
261 }
262 
NamedPipeRead(PVOID Object,LPVOID lpBuffer,DWORD nNumberOfBytesToRead,LPDWORD lpNumberOfBytesRead,LPOVERLAPPED lpOverlapped)263 BOOL NamedPipeRead(PVOID Object, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
264                    LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
265 {
266 	int io_status;
267 	WINPR_NAMED_PIPE* pipe;
268 	BOOL status = TRUE;
269 
270 	if (lpOverlapped)
271 	{
272 		WLog_ERR(TAG, "WinPR %s does not support the lpOverlapped parameter", __FUNCTION__);
273 		SetLastError(ERROR_NOT_SUPPORTED);
274 		return FALSE;
275 	}
276 
277 	pipe = (WINPR_NAMED_PIPE*)Object;
278 
279 	if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
280 	{
281 		if (pipe->clientfd == -1)
282 			return FALSE;
283 
284 		do
285 		{
286 			io_status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead);
287 		} while ((io_status < 0) && (errno == EINTR));
288 
289 		if (io_status == 0)
290 		{
291 			SetLastError(ERROR_BROKEN_PIPE);
292 			status = FALSE;
293 		}
294 		else if (io_status < 0)
295 		{
296 			status = FALSE;
297 
298 			switch (errno)
299 			{
300 				case EWOULDBLOCK:
301 					SetLastError(ERROR_NO_DATA);
302 					break;
303 
304 				default:
305 					SetLastError(ERROR_BROKEN_PIPE);
306 					break;
307 			}
308 		}
309 
310 		if (lpNumberOfBytesRead)
311 			*lpNumberOfBytesRead = io_status;
312 	}
313 	else
314 	{
315 		/* Overlapped I/O */
316 		if (!lpOverlapped)
317 			return FALSE;
318 
319 		if (pipe->clientfd == -1)
320 			return FALSE;
321 
322 		pipe->lpOverlapped = lpOverlapped;
323 #ifdef HAVE_SYS_AIO_H
324 		{
325 			int aio_status;
326 			struct aiocb cb;
327 			ZeroMemory(&cb, sizeof(struct aiocb));
328 			cb.aio_fildes = pipe->clientfd;
329 			cb.aio_buf = lpBuffer;
330 			cb.aio_nbytes = nNumberOfBytesToRead;
331 			cb.aio_offset = lpOverlapped->Offset;
332 			cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
333 			cb.aio_sigevent.sigev_signo = SIGIO;
334 			cb.aio_sigevent.sigev_value.sival_ptr = (void*)lpOverlapped;
335 			InstallAioSignalHandler();
336 			aio_status = aio_read(&cb);
337 			WLog_DBG(TAG, "aio_read status: %d", aio_status);
338 
339 			if (aio_status < 0)
340 				status = FALSE;
341 
342 			return status;
343 		}
344 #else
345 		/* synchronous behavior */
346 		lpOverlapped->Internal = 0;
347 		lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToRead;
348 		lpOverlapped->Pointer = (PVOID)lpBuffer;
349 		SetEvent(lpOverlapped->hEvent);
350 #endif
351 	}
352 
353 	return status;
354 }
355 
NamedPipeWrite(PVOID Object,LPCVOID lpBuffer,DWORD nNumberOfBytesToWrite,LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped)356 BOOL NamedPipeWrite(PVOID Object, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
357                     LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
358 {
359 	int io_status;
360 	WINPR_NAMED_PIPE* pipe;
361 	BOOL status = TRUE;
362 
363 	if (lpOverlapped)
364 	{
365 		WLog_ERR(TAG, "WinPR %s does not support the lpOverlapped parameter", __FUNCTION__);
366 		SetLastError(ERROR_NOT_SUPPORTED);
367 		return FALSE;
368 	}
369 
370 	pipe = (WINPR_NAMED_PIPE*)Object;
371 
372 	if (!(pipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
373 	{
374 		if (pipe->clientfd == -1)
375 			return FALSE;
376 
377 		do
378 		{
379 			io_status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite);
380 		} while ((io_status < 0) && (errno == EINTR));
381 
382 		if (io_status < 0)
383 		{
384 			*lpNumberOfBytesWritten = 0;
385 
386 			switch (errno)
387 			{
388 				case EWOULDBLOCK:
389 					io_status = 0;
390 					status = TRUE;
391 					break;
392 
393 				default:
394 					status = FALSE;
395 			}
396 		}
397 
398 		*lpNumberOfBytesWritten = io_status;
399 		return status;
400 	}
401 	else
402 	{
403 		/* Overlapped I/O */
404 		if (!lpOverlapped)
405 			return FALSE;
406 
407 		if (pipe->clientfd == -1)
408 			return FALSE;
409 
410 		pipe->lpOverlapped = lpOverlapped;
411 #ifdef HAVE_SYS_AIO_H
412 		{
413 			struct aiocb cb;
414 			ZeroMemory(&cb, sizeof(struct aiocb));
415 			cb.aio_fildes = pipe->clientfd;
416 			cb.aio_buf = (void*)lpBuffer;
417 			cb.aio_nbytes = nNumberOfBytesToWrite;
418 			cb.aio_offset = lpOverlapped->Offset;
419 			cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
420 			cb.aio_sigevent.sigev_signo = SIGIO;
421 			cb.aio_sigevent.sigev_value.sival_ptr = (void*)lpOverlapped;
422 			InstallAioSignalHandler();
423 			io_status = aio_write(&cb);
424 			WLog_DBG("aio_write status: %d", io_status);
425 
426 			if (io_status < 0)
427 				status = FALSE;
428 
429 			return status;
430 		}
431 #else
432 		/* synchronous behavior */
433 		lpOverlapped->Internal = 1;
434 		lpOverlapped->InternalHigh = (ULONG_PTR)nNumberOfBytesToWrite;
435 		lpOverlapped->Pointer = (PVOID)lpBuffer;
436 		SetEvent(lpOverlapped->hEvent);
437 #endif
438 	}
439 
440 	return TRUE;
441 }
442 
443 static HANDLE_OPS namedOps = { NamedPipeIsHandled,
444 	                           NamedPipeCloseHandle,
445 	                           NamedPipeGetFd,
446 	                           NULL, /* CleanupHandle */
447 	                           NamedPipeRead,
448 	                           NULL,
449 	                           NULL,
450 	                           NamedPipeWrite,
451 	                           NULL,
452 	                           NULL,
453 	                           NULL,
454 	                           NULL,
455 	                           NULL,
456 	                           NULL,
457 	                           NULL,
458 	                           NULL,
459 	                           NULL,
460 	                           NULL,
461 	                           NULL,
462 	                           NULL };
463 
InitWinPRPipeModule()464 static BOOL InitWinPRPipeModule()
465 {
466 	if (g_NamedPipeServerSockets)
467 		return TRUE;
468 
469 	g_NamedPipeServerSockets = ArrayList_New(FALSE);
470 	return g_NamedPipeServerSockets != NULL;
471 }
472 
473 /*
474  * Unnamed pipe
475  */
476 
CreatePipe(PHANDLE hReadPipe,PHANDLE hWritePipe,LPSECURITY_ATTRIBUTES lpPipeAttributes,DWORD nSize)477 BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes,
478                 DWORD nSize)
479 {
480 	int pipe_fd[2];
481 	WINPR_PIPE* pReadPipe;
482 	WINPR_PIPE* pWritePipe;
483 	pipe_fd[0] = -1;
484 	pipe_fd[1] = -1;
485 
486 	if (pipe(pipe_fd) < 0)
487 	{
488 		WLog_ERR(TAG, "failed to create pipe");
489 		return FALSE;
490 	}
491 
492 	pReadPipe = (WINPR_PIPE*)calloc(1, sizeof(WINPR_PIPE));
493 	pWritePipe = (WINPR_PIPE*)calloc(1, sizeof(WINPR_PIPE));
494 
495 	if (!pReadPipe || !pWritePipe)
496 	{
497 		free(pReadPipe);
498 		free(pWritePipe);
499 		return FALSE;
500 	}
501 
502 	pReadPipe->fd = pipe_fd[0];
503 	pWritePipe->fd = pipe_fd[1];
504 	WINPR_HANDLE_SET_TYPE_AND_MODE(pReadPipe, HANDLE_TYPE_ANONYMOUS_PIPE, WINPR_FD_READ);
505 	pReadPipe->ops = &ops;
506 	*((ULONG_PTR*)hReadPipe) = (ULONG_PTR)pReadPipe;
507 	WINPR_HANDLE_SET_TYPE_AND_MODE(pWritePipe, HANDLE_TYPE_ANONYMOUS_PIPE, WINPR_FD_READ);
508 	pWritePipe->ops = &ops;
509 	*((ULONG_PTR*)hWritePipe) = (ULONG_PTR)pWritePipe;
510 	return TRUE;
511 }
512 
513 /**
514  * Named pipe
515  */
516 
winpr_unref_named_pipe(WINPR_NAMED_PIPE * pNamedPipe)517 static void winpr_unref_named_pipe(WINPR_NAMED_PIPE* pNamedPipe)
518 {
519 	int index;
520 	NamedPipeServerSocketEntry* baseSocket;
521 
522 	if (!pNamedPipe)
523 		return;
524 
525 	assert(pNamedPipe->name);
526 	assert(g_NamedPipeServerSockets);
527 	// WLog_VRB(TAG, "%p (%s)", (void*) pNamedPipe, pNamedPipe->name);
528 	ArrayList_Lock(g_NamedPipeServerSockets);
529 
530 	for (index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
531 	{
532 		baseSocket =
533 		    (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
534 		assert(baseSocket->name);
535 
536 		if (!strcmp(baseSocket->name, pNamedPipe->name))
537 		{
538 			assert(baseSocket->references > 0);
539 			assert(baseSocket->serverfd != -1);
540 
541 			if (--baseSocket->references == 0)
542 			{
543 				// WLog_DBG(TAG, "removing shared server socked resource");
544 				// WLog_DBG(TAG, "closing shared serverfd %d", baseSocket->serverfd);
545 				ArrayList_Remove(g_NamedPipeServerSockets, baseSocket);
546 				close(baseSocket->serverfd);
547 				free(baseSocket->name);
548 				free(baseSocket);
549 			}
550 
551 			break;
552 		}
553 	}
554 
555 	ArrayList_Unlock(g_NamedPipeServerSockets);
556 }
557 
CreateNamedPipeA(LPCSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes)558 HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
559                         DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
560                         LPSECURITY_ATTRIBUTES lpSecurityAttributes)
561 {
562 	int index;
563 	char* lpPipePath;
564 	struct sockaddr_un s;
565 	WINPR_NAMED_PIPE* pNamedPipe = NULL;
566 	int serverfd = -1;
567 	NamedPipeServerSocketEntry* baseSocket = NULL;
568 
569 	if (dwOpenMode & FILE_FLAG_OVERLAPPED)
570 	{
571 		WLog_ERR(TAG, "WinPR %s does not support the FILE_FLAG_OVERLAPPED flag", __FUNCTION__);
572 		SetLastError(ERROR_NOT_SUPPORTED);
573 		return INVALID_HANDLE_VALUE;
574 	}
575 
576 	if (!lpName)
577 		return INVALID_HANDLE_VALUE;
578 
579 	if (!InitWinPRPipeModule())
580 		return INVALID_HANDLE_VALUE;
581 
582 	pNamedPipe = (WINPR_NAMED_PIPE*)calloc(1, sizeof(WINPR_NAMED_PIPE));
583 
584 	if (!pNamedPipe)
585 		return INVALID_HANDLE_VALUE;
586 
587 	ArrayList_Lock(g_NamedPipeServerSockets);
588 	WINPR_HANDLE_SET_TYPE_AND_MODE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE, WINPR_FD_READ);
589 	pNamedPipe->serverfd = -1;
590 	pNamedPipe->clientfd = -1;
591 
592 	if (!(pNamedPipe->name = _strdup(lpName)))
593 		goto out;
594 
595 	if (!(pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName)))
596 		goto out;
597 
598 	if (!(pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName)))
599 		goto out;
600 
601 	pNamedPipe->dwOpenMode = dwOpenMode;
602 	pNamedPipe->dwPipeMode = dwPipeMode;
603 	pNamedPipe->nMaxInstances = nMaxInstances;
604 	pNamedPipe->nOutBufferSize = nOutBufferSize;
605 	pNamedPipe->nInBufferSize = nInBufferSize;
606 	pNamedPipe->nDefaultTimeOut = nDefaultTimeOut;
607 	pNamedPipe->dwFlagsAndAttributes = dwOpenMode;
608 	pNamedPipe->clientfd = -1;
609 	pNamedPipe->ServerMode = TRUE;
610 	pNamedPipe->ops = &namedOps;
611 
612 	for (index = 0; index < ArrayList_Count(g_NamedPipeServerSockets); index++)
613 	{
614 		baseSocket =
615 		    (NamedPipeServerSocketEntry*)ArrayList_GetItem(g_NamedPipeServerSockets, index);
616 
617 		if (!strcmp(baseSocket->name, lpName))
618 		{
619 			serverfd = baseSocket->serverfd;
620 			// WLog_DBG(TAG, "using shared socked resource for pipe %p (%s)", (void*) pNamedPipe,
621 			// lpName);
622 			break;
623 		}
624 	}
625 
626 	/* If this is the first instance of the named pipe... */
627 	if (serverfd == -1)
628 	{
629 		/* Create the UNIX domain socket and start listening. */
630 		if (!(lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA()))
631 			goto out;
632 
633 		if (!winpr_PathFileExists(lpPipePath))
634 		{
635 			if (!CreateDirectoryA(lpPipePath, 0))
636 			{
637 				free(lpPipePath);
638 				goto out;
639 			}
640 
641 			UnixChangeFileMode(lpPipePath, 0xFFFF);
642 		}
643 
644 		free(lpPipePath);
645 
646 		if (winpr_PathFileExists(pNamedPipe->lpFilePath))
647 			winpr_DeleteFile(pNamedPipe->lpFilePath);
648 
649 		if ((serverfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
650 		{
651 			WLog_ERR(TAG, "CreateNamedPipeA: socket error, %s", strerror(errno));
652 			goto out;
653 		}
654 
655 		ZeroMemory(&s, sizeof(struct sockaddr_un));
656 		s.sun_family = AF_UNIX;
657 		sprintf_s(s.sun_path, ARRAYSIZE(s.sun_path), "%s", pNamedPipe->lpFilePath);
658 
659 		if (bind(serverfd, (struct sockaddr*)&s, sizeof(struct sockaddr_un)) == -1)
660 		{
661 			WLog_ERR(TAG, "CreateNamedPipeA: bind error, %s", strerror(errno));
662 			goto out;
663 		}
664 
665 		if (listen(serverfd, 2) == -1)
666 		{
667 			WLog_ERR(TAG, "CreateNamedPipeA: listen error, %s", strerror(errno));
668 			goto out;
669 		}
670 
671 		UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF);
672 
673 		if (!(baseSocket = (NamedPipeServerSocketEntry*)malloc(sizeof(NamedPipeServerSocketEntry))))
674 			goto out;
675 
676 		if (!(baseSocket->name = _strdup(lpName)))
677 		{
678 			free(baseSocket);
679 			goto out;
680 		}
681 
682 		baseSocket->serverfd = serverfd;
683 		baseSocket->references = 0;
684 
685 		if (ArrayList_Add(g_NamedPipeServerSockets, baseSocket) < 0)
686 		{
687 			free(baseSocket->name);
688 			goto out;
689 		}
690 
691 		// WLog_DBG(TAG, "created shared socked resource for pipe %p (%s). base serverfd = %d",
692 		// (void*) pNamedPipe, lpName, serverfd);
693 	}
694 
695 	pNamedPipe->serverfd = dup(baseSocket->serverfd);
696 	// WLog_DBG(TAG, "using serverfd %d (duplicated from %d)", pNamedPipe->serverfd,
697 	// baseSocket->serverfd);
698 	pNamedPipe->pfnUnrefNamedPipe = winpr_unref_named_pipe;
699 	baseSocket->references++;
700 
701 	if (dwOpenMode & FILE_FLAG_OVERLAPPED)
702 	{
703 #if 0
704 		int flags = fcntl(pNamedPipe->serverfd, F_GETFL);
705 
706 		if (flags != -1)
707 			fcntl(pNamedPipe->serverfd, F_SETFL, flags | O_NONBLOCK);
708 
709 #endif
710 	}
711 
712 	ArrayList_Unlock(g_NamedPipeServerSockets);
713 	return pNamedPipe;
714 out:
715 	NamedPipeCloseHandle(pNamedPipe);
716 
717 	if (serverfd != -1)
718 		close(serverfd);
719 
720 	ArrayList_Unlock(g_NamedPipeServerSockets);
721 	return INVALID_HANDLE_VALUE;
722 }
723 
CreateNamedPipeW(LPCWSTR lpName,DWORD dwOpenMode,DWORD dwPipeMode,DWORD nMaxInstances,DWORD nOutBufferSize,DWORD nInBufferSize,DWORD nDefaultTimeOut,LPSECURITY_ATTRIBUTES lpSecurityAttributes)724 HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
725                         DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
726                         LPSECURITY_ATTRIBUTES lpSecurityAttributes)
727 {
728 	WLog_ERR(TAG, "%s is not implemented", __FUNCTION__);
729 	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
730 	return NULL;
731 }
732 
ConnectNamedPipe(HANDLE hNamedPipe,LPOVERLAPPED lpOverlapped)733 BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped)
734 {
735 	int status;
736 	socklen_t length;
737 	struct sockaddr_un s;
738 	WINPR_NAMED_PIPE* pNamedPipe;
739 
740 	if (lpOverlapped)
741 	{
742 		WLog_ERR(TAG, "WinPR %s does not support the lpOverlapped parameter", __FUNCTION__);
743 		SetLastError(ERROR_NOT_SUPPORTED);
744 		return FALSE;
745 	}
746 
747 	if (!hNamedPipe)
748 		return FALSE;
749 
750 	pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
751 
752 	if (!(pNamedPipe->dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
753 	{
754 		length = sizeof(struct sockaddr_un);
755 		ZeroMemory(&s, sizeof(struct sockaddr_un));
756 		status = accept(pNamedPipe->serverfd, (struct sockaddr*)&s, &length);
757 
758 		if (status < 0)
759 		{
760 			WLog_ERR(TAG, "ConnectNamedPipe: accept error");
761 			return FALSE;
762 		}
763 
764 		pNamedPipe->clientfd = status;
765 		pNamedPipe->ServerMode = FALSE;
766 	}
767 	else
768 	{
769 		if (!lpOverlapped)
770 			return FALSE;
771 
772 		if (pNamedPipe->serverfd == -1)
773 			return FALSE;
774 
775 		pNamedPipe->lpOverlapped = lpOverlapped;
776 		/* synchronous behavior */
777 		lpOverlapped->Internal = 2;
778 		lpOverlapped->InternalHigh = (ULONG_PTR)0;
779 		lpOverlapped->Pointer = (PVOID)NULL;
780 		SetEvent(lpOverlapped->hEvent);
781 	}
782 
783 	return TRUE;
784 }
785 
DisconnectNamedPipe(HANDLE hNamedPipe)786 BOOL DisconnectNamedPipe(HANDLE hNamedPipe)
787 {
788 	WINPR_NAMED_PIPE* pNamedPipe;
789 	pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
790 
791 	if (pNamedPipe->clientfd != -1)
792 	{
793 		close(pNamedPipe->clientfd);
794 		pNamedPipe->clientfd = -1;
795 	}
796 
797 	return TRUE;
798 }
799 
PeekNamedPipe(HANDLE hNamedPipe,LPVOID lpBuffer,DWORD nBufferSize,LPDWORD lpBytesRead,LPDWORD lpTotalBytesAvail,LPDWORD lpBytesLeftThisMessage)800 BOOL PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesRead,
801                    LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage)
802 {
803 	WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
804 	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
805 	return FALSE;
806 }
807 
TransactNamedPipe(HANDLE hNamedPipe,LPVOID lpInBuffer,DWORD nInBufferSize,LPVOID lpOutBuffer,DWORD nOutBufferSize,LPDWORD lpBytesRead,LPOVERLAPPED lpOverlapped)808 BOOL TransactNamedPipe(HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize,
809                        LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesRead,
810                        LPOVERLAPPED lpOverlapped)
811 {
812 	WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
813 	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
814 	return FALSE;
815 }
816 
WaitNamedPipeA(LPCSTR lpNamedPipeName,DWORD nTimeOut)817 BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut)
818 {
819 	BOOL status;
820 	DWORD nWaitTime;
821 	char* lpFilePath;
822 	DWORD dwSleepInterval;
823 
824 	if (!lpNamedPipeName)
825 		return FALSE;
826 
827 	lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpNamedPipeName);
828 
829 	if (!lpFilePath)
830 		return FALSE;
831 
832 	if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
833 		nTimeOut = 50;
834 
835 	nWaitTime = 0;
836 	status = TRUE;
837 	dwSleepInterval = 10;
838 
839 	while (!winpr_PathFileExists(lpFilePath))
840 	{
841 		Sleep(dwSleepInterval);
842 		nWaitTime += dwSleepInterval;
843 
844 		if (nWaitTime >= nTimeOut)
845 		{
846 			status = FALSE;
847 			break;
848 		}
849 	}
850 
851 	free(lpFilePath);
852 	return status;
853 }
854 
WaitNamedPipeW(LPCWSTR lpNamedPipeName,DWORD nTimeOut)855 BOOL WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut)
856 {
857 	WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
858 	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
859 	return FALSE;
860 }
861 
SetNamedPipeHandleState(HANDLE hNamedPipe,LPDWORD lpMode,LPDWORD lpMaxCollectionCount,LPDWORD lpCollectDataTimeout)862 BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount,
863                              LPDWORD lpCollectDataTimeout)
864 {
865 	int fd;
866 	int flags;
867 	WINPR_NAMED_PIPE* pNamedPipe;
868 	pNamedPipe = (WINPR_NAMED_PIPE*)hNamedPipe;
869 
870 	if (lpMode)
871 	{
872 		pNamedPipe->dwPipeMode = *lpMode;
873 		fd = (pNamedPipe->ServerMode) ? pNamedPipe->serverfd : pNamedPipe->clientfd;
874 
875 		if (fd == -1)
876 			return FALSE;
877 
878 		flags = fcntl(fd, F_GETFL);
879 
880 		if (flags < 0)
881 			return FALSE;
882 
883 		if (pNamedPipe->dwPipeMode & PIPE_NOWAIT)
884 			flags = (flags | O_NONBLOCK);
885 		else
886 			flags = (flags & ~(O_NONBLOCK));
887 
888 		if (fcntl(fd, F_SETFL, flags) < 0)
889 			return FALSE;
890 	}
891 
892 	if (lpMaxCollectionCount)
893 	{
894 	}
895 
896 	if (lpCollectDataTimeout)
897 	{
898 	}
899 
900 	return TRUE;
901 }
902 
ImpersonateNamedPipeClient(HANDLE hNamedPipe)903 BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe)
904 {
905 	WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
906 	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
907 	return FALSE;
908 }
909 
GetNamedPipeClientComputerNameA(HANDLE Pipe,LPCSTR ClientComputerName,ULONG ClientComputerNameLength)910 BOOL GetNamedPipeClientComputerNameA(HANDLE Pipe, LPCSTR ClientComputerName,
911                                      ULONG ClientComputerNameLength)
912 {
913 	WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
914 	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
915 	return FALSE;
916 }
917 
GetNamedPipeClientComputerNameW(HANDLE Pipe,LPCWSTR ClientComputerName,ULONG ClientComputerNameLength)918 BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComputerName,
919                                      ULONG ClientComputerNameLength)
920 {
921 	WLog_ERR(TAG, "%s: Not implemented", __FUNCTION__);
922 	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
923 	return FALSE;
924 }
925 
926 #endif
927