Coverage Report

Created: 2026-01-16 07:05

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