Coverage Report

Created: 2026-09-03 07:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/rpc_server/srv_pipe_hnd.c
Line
Count
Source
1
/*
2
 *  Unix SMB/CIFS implementation.
3
 *  RPC Pipe client / server routines
4
 *  Copyright (C) Andrew Tridgell              1992-1998,
5
 *  Largely re-written : 2005
6
 *  Copyright (C) Jeremy Allison    1998 - 2005
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 3 of the License, or
11
 *  (at your option) any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "includes.h"
23
#include "fake_file.h"
24
#include "rpc_dce.h"
25
#include "ntdomain.h"
26
#include "rpc_server/rpc_ncacn_np.h"
27
#include "rpc_server/srv_pipe_hnd.h"
28
#include "rpc_client/local_np.h"
29
#include "rpc_server/rpc_server.h"
30
#include "rpc_server/rpc_config.h"
31
#include "../lib/tsocket/tsocket.h"
32
#include "../lib/util/tevent_ntstatus.h"
33
#include "../lib/util/util_str_escape.h"
34
#include "librpc/ndr/ndr_table.h"
35
36
#undef DBGC_CLASS
37
0
#define DBGC_CLASS DBGC_RPC_SRV
38
39
bool fsp_is_np(struct files_struct *fsp)
40
0
{
41
0
  enum FAKE_FILE_TYPE type;
42
43
0
  if ((fsp == NULL) || (fsp->fake_file_handle == NULL)) {
44
0
    return false;
45
0
  }
46
47
0
  type = fsp->fake_file_handle->type;
48
49
0
  return (type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY);
50
0
}
51
52
struct np_wait_exists_state {
53
  const char *name;
54
};
55
56
static void np_wait_exists_done(struct tevent_req *subreq);
57
58
struct tevent_req *np_wait_exists_send(
59
  TALLOC_CTX *mem_ctx,
60
  struct tevent_context *ev,
61
  const char *name,
62
  const struct tsocket_address *remote_client_address,
63
  const struct tsocket_address *local_server_address,
64
  struct auth_session_info *session_info)
65
0
{
66
0
  struct tevent_req *req = NULL, *subreq = NULL;
67
0
  struct np_wait_exists_state *state = NULL;
68
69
0
  req = tevent_req_create(mem_ctx, &state, struct np_wait_exists_state);
70
0
  if (req == NULL) {
71
0
    return NULL;
72
0
  }
73
0
  state->name = name;
74
75
0
  subreq = local_np_connect_send(state,
76
0
               ev,
77
0
               name,
78
0
               NCACN_NP,
79
0
               NULL,
80
0
               remote_client_address,
81
0
               NULL,
82
0
               local_server_address,
83
0
               session_info,
84
0
               false, /* need_idle_server */
85
0
               true); /* probe_only */
86
0
  if (tevent_req_nomem(subreq, req)) {
87
0
    return tevent_req_post(req, ev);
88
0
  }
89
0
  tevent_req_set_callback(subreq, np_wait_exists_done, req);
90
0
  return req;
91
0
}
92
93
static void np_wait_exists_done(struct tevent_req *subreq)
94
0
{
95
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
96
0
                struct tevent_req);
97
0
  struct np_wait_exists_state *state = tevent_req_data(
98
0
    req, struct np_wait_exists_state);
99
0
  struct tstream_context *npa_tstream = NULL;
100
0
  int ret;
101
102
0
  ret = local_np_connect_recv(subreq, state, &npa_tstream);
103
0
  TALLOC_FREE(subreq);
104
105
0
  if (ret == EEXIST) {
106
0
    DBG_DEBUG("local_np_connect(%s, probe_only) returned %s\n",
107
0
        log_escape(state, state->name),
108
0
        strerror(ret));
109
0
    tevent_req_done(req);
110
0
    return;
111
0
  }
112
113
0
  if (ret == ENOENT) {
114
0
    DBG_INFO("local_np_connect(%s, probe_only) returned %s\n",
115
0
       log_escape(state, state->name),
116
0
       strerror(ret));
117
0
    tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
118
0
    return;
119
0
  }
120
121
0
  if (ret == 0) {
122
0
    DBG_ERR("local_np_connect(%s, probe_only) returned 0\n",
123
0
      log_escape(state, state->name));
124
0
    tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
125
0
    return;
126
0
  }
127
128
0
  DBG_WARNING("local_np_connect(%s, probe_only) returned %s\n",
129
0
        log_escape(state, state->name),
130
0
        strerror(ret));
131
0
  tevent_req_nterror(req, map_nt_error_from_unix(ret));
132
0
}
133
134
NTSTATUS np_wait_exists_recv(struct tevent_req *req)
135
0
{
136
0
  return tevent_req_simple_recv_ntstatus(req);
137
0
}
138
139
NTSTATUS np_open(TALLOC_CTX *mem_ctx, const char *name,
140
     const struct tsocket_address *remote_client_address,
141
     const struct tsocket_address *local_server_address,
142
     struct auth_session_info *session_info,
143
     struct fake_file_handle **phandle)
144
0
{
145
0
  struct fake_file_handle *handle;
146
0
  struct npa_state *npa = NULL;
147
0
  int ret;
148
149
0
  handle = talloc(mem_ctx, struct fake_file_handle);
150
0
  if (handle == NULL) {
151
0
    return NT_STATUS_NO_MEMORY;
152
0
  }
153
154
0
  npa = npa_state_init(handle);
155
0
  if (npa == NULL) {
156
0
    TALLOC_FREE(handle);
157
0
    return NT_STATUS_NO_MEMORY;
158
0
  }
159
0
  *handle = (struct fake_file_handle) {
160
0
    .type = FAKE_FILE_TYPE_NAMED_PIPE_PROXY,
161
0
    .private_data = npa,
162
0
  };
163
164
0
  ret = local_np_connect(
165
0
    name,
166
0
    NCACN_NP,
167
0
    NULL,
168
0
    remote_client_address,
169
0
    NULL,
170
0
    local_server_address,
171
0
    session_info,
172
0
    false, /* need_idle_server */
173
0
    false, /* probe_only */
174
0
    npa,
175
0
    &npa->stream);
176
0
  if (ret != 0) {
177
0
    DBG_DEBUG("local_np_connect failed: %s\n",
178
0
        strerror(ret));
179
0
    TALLOC_FREE(handle);
180
0
    return map_nt_error_from_unix(ret);
181
0
  }
182
183
0
  *phandle = handle;
184
185
0
  return NT_STATUS_OK;
186
0
}
187
188
bool np_read_in_progress(struct fake_file_handle *handle)
189
0
{
190
0
  if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
191
0
    struct npa_state *p =
192
0
      talloc_get_type_abort(handle->private_data,
193
0
                struct npa_state);
194
0
    size_t read_count;
195
196
0
    read_count = tevent_queue_length(p->read_queue);
197
0
    if (read_count > 0) {
198
0
      return true;
199
0
    }
200
201
0
    return false;
202
0
  }
203
204
0
  return false;
205
0
}
206
207
struct np_write_state {
208
  struct tevent_context *ev;
209
  struct npa_state *p;
210
  struct iovec iov;
211
  ssize_t nwritten;
212
};
213
214
static void np_write_done(struct tevent_req *subreq);
215
216
struct tevent_req *np_write_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
217
         struct fake_file_handle *handle,
218
         const uint8_t *data, size_t len)
219
0
{
220
0
  struct tevent_req *req;
221
0
  struct np_write_state *state;
222
0
  struct npa_state *p = NULL;
223
0
  struct tevent_req *subreq = NULL;
224
225
0
  DBG_INFO("len: %zu\n", len);
226
0
  dump_data(50, data, len);
227
228
0
  req = tevent_req_create(mem_ctx, &state, struct np_write_state);
229
0
  if (req == NULL) {
230
0
    return NULL;
231
0
  }
232
233
0
  if (handle->type != FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
234
0
    tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
235
0
    return tevent_req_post(req, ev);
236
0
  }
237
238
0
  if (len == 0) {
239
0
    state->nwritten = 0;
240
0
    tevent_req_done(req);
241
0
    return tevent_req_post(req, ev);
242
0
  }
243
244
0
  p = talloc_get_type_abort(handle->private_data, struct npa_state);
245
246
0
  state->ev = ev;
247
0
  state->p = p;
248
0
  state->iov.iov_base = discard_const_p(void, data);
249
0
  state->iov.iov_len = len;
250
251
0
  subreq = tstream_writev_queue_send(
252
0
    state, ev, p->stream, p->write_queue, &state->iov, 1);
253
0
  if (tevent_req_nomem(subreq, req)) {
254
0
    return tevent_req_post(req, ev);
255
0
  }
256
0
  tevent_req_set_callback(subreq, np_write_done, req);
257
0
  return req;
258
0
}
259
260
static void np_write_done(struct tevent_req *subreq)
261
0
{
262
0
  struct tevent_req *req = tevent_req_callback_data(
263
0
    subreq, struct tevent_req);
264
0
  struct np_write_state *state = tevent_req_data(
265
0
    req, struct np_write_state);
266
0
  ssize_t received;
267
0
  int err;
268
269
0
  received = tstream_writev_queue_recv(subreq, &err);
270
0
  if (received < 0) {
271
0
    tevent_req_nterror(req, map_nt_error_from_unix(err));
272
0
    return;
273
0
  }
274
0
  state->nwritten = received;
275
0
  tevent_req_done(req);
276
0
}
277
278
NTSTATUS np_write_recv(struct tevent_req *req, ssize_t *pnwritten)
279
0
{
280
0
  struct np_write_state *state = tevent_req_data(
281
0
    req, struct np_write_state);
282
0
  NTSTATUS status;
283
284
0
  if (tevent_req_is_nterror(req, &status)) {
285
0
    return status;
286
0
  }
287
0
  *pnwritten = state->nwritten;
288
0
  return NT_STATUS_OK;
289
0
}
290
291
struct np_ipc_readv_next_vector_state {
292
  uint8_t *buf;
293
  size_t len;
294
  off_t ofs;
295
  size_t remaining;
296
};
297
298
static void np_ipc_readv_next_vector_init(struct np_ipc_readv_next_vector_state *s,
299
            uint8_t *buf, size_t len)
300
0
{
301
0
  ZERO_STRUCTP(s);
302
303
0
  s->buf = buf;
304
0
  s->len = MIN(len, UINT16_MAX);
305
0
}
306
307
static int np_ipc_readv_next_vector(struct tstream_context *stream,
308
            void *private_data,
309
            TALLOC_CTX *mem_ctx,
310
            struct iovec **_vector,
311
            size_t *count)
312
0
{
313
0
  struct np_ipc_readv_next_vector_state *state =
314
0
    (struct np_ipc_readv_next_vector_state *)private_data;
315
0
  struct iovec *vector;
316
0
  ssize_t pending;
317
0
  size_t wanted;
318
319
0
  if (state->ofs == state->len) {
320
0
    *_vector = NULL;
321
0
    *count = 0;
322
0
    return 0;
323
0
  }
324
325
0
  pending = tstream_pending_bytes(stream);
326
0
  if (pending == -1) {
327
0
    return -1;
328
0
  }
329
330
0
  if (pending == 0 && state->ofs != 0) {
331
    /* return a short read */
332
0
    *_vector = NULL;
333
0
    *count = 0;
334
0
    return 0;
335
0
  }
336
337
0
  if (pending == 0) {
338
    /* we want at least one byte and recheck again */
339
0
    wanted = 1;
340
0
  } else {
341
0
    size_t missing = state->len - state->ofs;
342
0
    if (pending > missing) {
343
      /* there's more available */
344
0
      state->remaining = pending - missing;
345
0
      wanted = missing;
346
0
    } else {
347
      /* read what we can get and recheck in the next cycle */
348
0
      wanted = pending;
349
0
    }
350
0
  }
351
352
0
  vector = talloc_array(mem_ctx, struct iovec, 1);
353
0
  if (!vector) {
354
0
    return -1;
355
0
  }
356
357
0
  vector[0].iov_base = state->buf + state->ofs;
358
0
  vector[0].iov_len = wanted;
359
360
0
  state->ofs += wanted;
361
362
0
  *_vector = vector;
363
0
  *count = 1;
364
0
  return 0;
365
0
}
366
367
struct np_read_zero_state;
368
369
struct np_read_state {
370
  struct npa_state *p;
371
  struct np_ipc_readv_next_vector_state next_vector;
372
373
  ssize_t nread;
374
  bool is_data_outstanding;
375
376
  struct np_read_zero_state *zs;
377
};
378
379
struct np_read_zero_state {
380
  struct np_read_state *state;
381
  struct tevent_req *req;
382
};
383
384
static int np_read_zero_state_destructor(struct np_read_zero_state *zs)
385
0
{
386
0
  if (zs->state != NULL) {
387
0
    zs->state->zs = NULL;
388
0
    zs->state = NULL;
389
0
  }
390
0
  tevent_req_nterror(zs->req, NT_STATUS_PIPE_BROKEN);
391
0
  return 0;
392
0
}
393
394
static void np_read_send_cleanup(struct tevent_req *req,
395
         enum tevent_req_state req_state)
396
0
{
397
0
  struct np_read_state *state = tevent_req_data(
398
0
    req, struct np_read_state);
399
400
0
  if (state->zs != NULL) {
401
0
    talloc_set_destructor(state->zs, NULL);
402
0
    TALLOC_FREE(state->zs);
403
0
  }
404
0
}
405
406
static void np_read_done(struct tevent_req *subreq);
407
408
struct tevent_req *np_read_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
409
        struct fake_file_handle *handle,
410
        uint8_t *data, size_t len)
411
0
{
412
0
  struct tevent_req *req;
413
0
  struct np_read_state *state;
414
0
  struct npa_state *p = NULL;
415
0
  struct tevent_req *subreq = NULL;
416
417
0
  req = tevent_req_create(mem_ctx, &state, struct np_read_state);
418
0
  if (req == NULL) {
419
0
    return NULL;
420
0
  }
421
422
0
  tevent_req_set_cleanup_fn(req, np_read_send_cleanup);
423
424
0
  if (handle->type != FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
425
0
    tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
426
0
    return tevent_req_post(req, ev);
427
0
  }
428
429
0
  p = talloc_get_type_abort(handle->private_data, struct npa_state);
430
431
0
  if (len == 0) {
432
0
    state->zs = talloc_zero(p, struct np_read_zero_state);
433
0
    if (tevent_req_nomem(state->zs, req)) {
434
0
      return tevent_req_post(req, ev);
435
0
    }
436
0
    talloc_set_destructor(state->zs,
437
0
              np_read_zero_state_destructor);
438
0
    state->zs->state = state;
439
0
    state->zs->req = req;
440
0
    return req;
441
0
  }
442
443
0
  np_ipc_readv_next_vector_init(&state->next_vector, data, len);
444
445
0
  subreq = tstream_readv_pdu_queue_send(
446
0
    state,
447
0
    ev,
448
0
    p->stream,
449
0
    p->read_queue,
450
0
    np_ipc_readv_next_vector,
451
0
    &state->next_vector);
452
0
  if (tevent_req_nomem(subreq, req)) {
453
0
    return tevent_req_post(req, ev);
454
0
  }
455
0
  tevent_req_set_callback(subreq, np_read_done, req);
456
0
  return req;
457
0
}
458
459
static void np_read_done(struct tevent_req *subreq)
460
0
{
461
0
  struct tevent_req *req = tevent_req_callback_data(
462
0
    subreq, struct tevent_req);
463
0
  struct np_read_state *state = tevent_req_data(
464
0
    req, struct np_read_state);
465
0
  ssize_t ret;
466
0
  int err;
467
468
0
  ret = tstream_readv_pdu_queue_recv(subreq, &err);
469
0
  TALLOC_FREE(subreq);
470
0
  if (ret == -1) {
471
0
    tevent_req_nterror(req, map_nt_error_from_unix(err));
472
0
    return;
473
0
  }
474
475
0
  state->nread = ret;
476
0
  state->is_data_outstanding = (state->next_vector.remaining > 0);
477
478
0
  tevent_req_done(req);
479
0
  return;
480
0
}
481
482
NTSTATUS np_read_recv(struct tevent_req *req, ssize_t *nread,
483
          bool *is_data_outstanding)
484
0
{
485
0
  struct np_read_state *state = tevent_req_data(
486
0
    req, struct np_read_state);
487
0
  NTSTATUS status;
488
489
0
  if (tevent_req_is_nterror(req, &status)) {
490
0
    return status;
491
0
  }
492
493
0
  DEBUG(10, ("Received %d bytes. There is %smore data outstanding\n",
494
0
       (int)state->nread, state->is_data_outstanding?"":"no "));
495
496
0
  *nread = state->nread;
497
0
  *is_data_outstanding = state->is_data_outstanding;
498
0
  return NT_STATUS_OK;
499
0
}