Coverage Report

Created: 2025-07-01 06:46

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