Coverage Report

Created: 2026-02-14 07:07

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 "librpc/ndr/ndr_table.h"
34
35
#undef DBGC_CLASS
36
0
#define DBGC_CLASS DBGC_RPC_SRV
37
38
bool fsp_is_np(struct files_struct *fsp)
39
0
{
40
0
  enum FAKE_FILE_TYPE type;
41
42
0
  if ((fsp == NULL) || (fsp->fake_file_handle == NULL)) {
43
0
    return false;
44
0
  }
45
46
0
  type = fsp->fake_file_handle->type;
47
48
0
  return (type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY);
49
0
}
50
51
NTSTATUS np_open(TALLOC_CTX *mem_ctx, const char *name,
52
     const struct tsocket_address *remote_client_address,
53
     const struct tsocket_address *local_server_address,
54
     struct auth_session_info *session_info,
55
     struct tevent_context *ev_ctx,
56
     struct messaging_context *msg_ctx,
57
     struct dcesrv_context *dce_ctx,
58
     struct fake_file_handle **phandle)
59
0
{
60
0
  struct fake_file_handle *handle;
61
0
  struct npa_state *npa = NULL;
62
0
  int ret;
63
64
0
  handle = talloc(mem_ctx, struct fake_file_handle);
65
0
  if (handle == NULL) {
66
0
    return NT_STATUS_NO_MEMORY;
67
0
  }
68
69
0
  npa = npa_state_init(handle);
70
0
  if (npa == NULL) {
71
0
    TALLOC_FREE(handle);
72
0
    return NT_STATUS_NO_MEMORY;
73
0
  }
74
0
  *handle = (struct fake_file_handle) {
75
0
    .type = FAKE_FILE_TYPE_NAMED_PIPE_PROXY,
76
0
    .private_data = npa,
77
0
  };
78
79
0
  ret = local_np_connect(
80
0
    name,
81
0
    NCACN_NP,
82
0
    NULL,
83
0
    remote_client_address,
84
0
    NULL,
85
0
    local_server_address,
86
0
    session_info,
87
0
    false,
88
0
    npa,
89
0
    &npa->stream);
90
0
  if (ret != 0) {
91
0
    DBG_DEBUG("local_np_connect failed: %s\n",
92
0
        strerror(ret));
93
0
    TALLOC_FREE(handle);
94
0
    return map_nt_error_from_unix(ret);
95
0
  }
96
97
0
  *phandle = handle;
98
99
0
  return NT_STATUS_OK;
100
0
}
101
102
bool np_read_in_progress(struct fake_file_handle *handle)
103
0
{
104
0
  if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
105
0
    struct npa_state *p =
106
0
      talloc_get_type_abort(handle->private_data,
107
0
                struct npa_state);
108
0
    size_t read_count;
109
110
0
    read_count = tevent_queue_length(p->read_queue);
111
0
    if (read_count > 0) {
112
0
      return true;
113
0
    }
114
115
0
    return false;
116
0
  }
117
118
0
  return false;
119
0
}
120
121
struct np_write_state {
122
  struct tevent_context *ev;
123
  struct npa_state *p;
124
  struct iovec iov;
125
  ssize_t nwritten;
126
};
127
128
static void np_write_done(struct tevent_req *subreq);
129
130
struct tevent_req *np_write_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
131
         struct fake_file_handle *handle,
132
         const uint8_t *data, size_t len)
133
0
{
134
0
  struct tevent_req *req;
135
0
  struct np_write_state *state;
136
0
  struct npa_state *p = NULL;
137
0
  struct tevent_req *subreq = NULL;
138
139
0
  DBG_INFO("len: %zu\n", len);
140
0
  dump_data(50, data, len);
141
142
0
  req = tevent_req_create(mem_ctx, &state, struct np_write_state);
143
0
  if (req == NULL) {
144
0
    return NULL;
145
0
  }
146
147
0
  if (handle->type != FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
148
0
    tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
149
0
    return tevent_req_post(req, ev);
150
0
  }
151
152
0
  if (len == 0) {
153
0
    state->nwritten = 0;
154
0
    tevent_req_done(req);
155
0
    return tevent_req_post(req, ev);
156
0
  }
157
158
0
  p = talloc_get_type_abort(handle->private_data, struct npa_state);
159
160
0
  state->ev = ev;
161
0
  state->p = p;
162
0
  state->iov.iov_base = discard_const_p(void, data);
163
0
  state->iov.iov_len = len;
164
165
0
  subreq = tstream_writev_queue_send(
166
0
    state, ev, p->stream, p->write_queue, &state->iov, 1);
167
0
  if (tevent_req_nomem(subreq, req)) {
168
0
    return tevent_req_post(req, ev);
169
0
  }
170
0
  tevent_req_set_callback(subreq, np_write_done, req);
171
0
  return req;
172
0
}
173
174
static void np_write_done(struct tevent_req *subreq)
175
0
{
176
0
  struct tevent_req *req = tevent_req_callback_data(
177
0
    subreq, struct tevent_req);
178
0
  struct np_write_state *state = tevent_req_data(
179
0
    req, struct np_write_state);
180
0
  ssize_t received;
181
0
  int err;
182
183
0
  received = tstream_writev_queue_recv(subreq, &err);
184
0
  if (received < 0) {
185
0
    tevent_req_nterror(req, map_nt_error_from_unix(err));
186
0
    return;
187
0
  }
188
0
  state->nwritten = received;
189
0
  tevent_req_done(req);
190
0
}
191
192
NTSTATUS np_write_recv(struct tevent_req *req, ssize_t *pnwritten)
193
0
{
194
0
  struct np_write_state *state = tevent_req_data(
195
0
    req, struct np_write_state);
196
0
  NTSTATUS status;
197
198
0
  if (tevent_req_is_nterror(req, &status)) {
199
0
    return status;
200
0
  }
201
0
  *pnwritten = state->nwritten;
202
0
  return NT_STATUS_OK;
203
0
}
204
205
struct np_ipc_readv_next_vector_state {
206
  uint8_t *buf;
207
  size_t len;
208
  off_t ofs;
209
  size_t remaining;
210
};
211
212
static void np_ipc_readv_next_vector_init(struct np_ipc_readv_next_vector_state *s,
213
            uint8_t *buf, size_t len)
214
0
{
215
0
  ZERO_STRUCTP(s);
216
217
0
  s->buf = buf;
218
0
  s->len = MIN(len, UINT16_MAX);
219
0
}
220
221
static int np_ipc_readv_next_vector(struct tstream_context *stream,
222
            void *private_data,
223
            TALLOC_CTX *mem_ctx,
224
            struct iovec **_vector,
225
            size_t *count)
226
0
{
227
0
  struct np_ipc_readv_next_vector_state *state =
228
0
    (struct np_ipc_readv_next_vector_state *)private_data;
229
0
  struct iovec *vector;
230
0
  ssize_t pending;
231
0
  size_t wanted;
232
233
0
  if (state->ofs == state->len) {
234
0
    *_vector = NULL;
235
0
    *count = 0;
236
0
    return 0;
237
0
  }
238
239
0
  pending = tstream_pending_bytes(stream);
240
0
  if (pending == -1) {
241
0
    return -1;
242
0
  }
243
244
0
  if (pending == 0 && state->ofs != 0) {
245
    /* return a short read */
246
0
    *_vector = NULL;
247
0
    *count = 0;
248
0
    return 0;
249
0
  }
250
251
0
  if (pending == 0) {
252
    /* we want at least one byte and recheck again */
253
0
    wanted = 1;
254
0
  } else {
255
0
    size_t missing = state->len - state->ofs;
256
0
    if (pending > missing) {
257
      /* there's more available */
258
0
      state->remaining = pending - missing;
259
0
      wanted = missing;
260
0
    } else {
261
      /* read what we can get and recheck in the next cycle */
262
0
      wanted = pending;
263
0
    }
264
0
  }
265
266
0
  vector = talloc_array(mem_ctx, struct iovec, 1);
267
0
  if (!vector) {
268
0
    return -1;
269
0
  }
270
271
0
  vector[0].iov_base = state->buf + state->ofs;
272
0
  vector[0].iov_len = wanted;
273
274
0
  state->ofs += wanted;
275
276
0
  *_vector = vector;
277
0
  *count = 1;
278
0
  return 0;
279
0
}
280
281
struct np_read_zero_state;
282
283
struct np_read_state {
284
  struct npa_state *p;
285
  struct np_ipc_readv_next_vector_state next_vector;
286
287
  ssize_t nread;
288
  bool is_data_outstanding;
289
290
  struct np_read_zero_state *zs;
291
};
292
293
struct np_read_zero_state {
294
  struct np_read_state *state;
295
  struct tevent_req *req;
296
};
297
298
static int np_read_zero_state_destructor(struct np_read_zero_state *zs)
299
0
{
300
0
  if (zs->state != NULL) {
301
0
    zs->state->zs = NULL;
302
0
    zs->state = NULL;
303
0
  }
304
0
  tevent_req_nterror(zs->req, NT_STATUS_PIPE_BROKEN);
305
0
  return 0;
306
0
}
307
308
static void np_read_send_cleanup(struct tevent_req *req,
309
         enum tevent_req_state req_state)
310
0
{
311
0
  struct np_read_state *state = tevent_req_data(
312
0
    req, struct np_read_state);
313
314
0
  if (state->zs != NULL) {
315
0
    talloc_set_destructor(state->zs, NULL);
316
0
    TALLOC_FREE(state->zs);
317
0
  }
318
0
}
319
320
static void np_read_done(struct tevent_req *subreq);
321
322
struct tevent_req *np_read_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
323
        struct fake_file_handle *handle,
324
        uint8_t *data, size_t len)
325
0
{
326
0
  struct tevent_req *req;
327
0
  struct np_read_state *state;
328
0
  struct npa_state *p = NULL;
329
0
  struct tevent_req *subreq = NULL;
330
331
0
  req = tevent_req_create(mem_ctx, &state, struct np_read_state);
332
0
  if (req == NULL) {
333
0
    return NULL;
334
0
  }
335
336
0
  tevent_req_set_cleanup_fn(req, np_read_send_cleanup);
337
338
0
  if (handle->type != FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
339
0
    tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
340
0
    return tevent_req_post(req, ev);
341
0
  }
342
343
0
  p = talloc_get_type_abort(handle->private_data, struct npa_state);
344
345
0
  if (len == 0) {
346
0
    state->zs = talloc_zero(p, struct np_read_zero_state);
347
0
    if (tevent_req_nomem(state->zs, req)) {
348
0
      return tevent_req_post(req, ev);
349
0
    }
350
0
    talloc_set_destructor(state->zs,
351
0
              np_read_zero_state_destructor);
352
0
    state->zs->state = state;
353
0
    state->zs->req = req;
354
0
    return req;
355
0
  }
356
357
0
  np_ipc_readv_next_vector_init(&state->next_vector, data, len);
358
359
0
  subreq = tstream_readv_pdu_queue_send(
360
0
    state,
361
0
    ev,
362
0
    p->stream,
363
0
    p->read_queue,
364
0
    np_ipc_readv_next_vector,
365
0
    &state->next_vector);
366
0
  if (tevent_req_nomem(subreq, req)) {
367
0
    return tevent_req_post(req, ev);
368
0
  }
369
0
  tevent_req_set_callback(subreq, np_read_done, req);
370
0
  return req;
371
0
}
372
373
static void np_read_done(struct tevent_req *subreq)
374
0
{
375
0
  struct tevent_req *req = tevent_req_callback_data(
376
0
    subreq, struct tevent_req);
377
0
  struct np_read_state *state = tevent_req_data(
378
0
    req, struct np_read_state);
379
0
  ssize_t ret;
380
0
  int err;
381
382
0
  ret = tstream_readv_pdu_queue_recv(subreq, &err);
383
0
  TALLOC_FREE(subreq);
384
0
  if (ret == -1) {
385
0
    tevent_req_nterror(req, map_nt_error_from_unix(err));
386
0
    return;
387
0
  }
388
389
0
  state->nread = ret;
390
0
  state->is_data_outstanding = (state->next_vector.remaining > 0);
391
392
0
  tevent_req_done(req);
393
0
  return;
394
0
}
395
396
NTSTATUS np_read_recv(struct tevent_req *req, ssize_t *nread,
397
          bool *is_data_outstanding)
398
0
{
399
0
  struct np_read_state *state = tevent_req_data(
400
0
    req, struct np_read_state);
401
0
  NTSTATUS status;
402
403
0
  if (tevent_req_is_nterror(req, &status)) {
404
0
    return status;
405
0
  }
406
407
0
  DEBUG(10, ("Received %d bytes. There is %smore data outstanding\n",
408
0
       (int)state->nread, state->is_data_outstanding?"":"no "));
409
410
0
  *nread = state->nread;
411
0
  *is_data_outstanding = state->is_data_outstanding;
412
0
  return NT_STATUS_OK;
413
0
}