Coverage Report

Created: 2024-05-20 06:11

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