Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/librpc/rpc/dcerpc_smb.c
Line
Count
Source
1
/* 
2
   Unix SMB/CIFS implementation.
3
4
   dcerpc over SMB transport
5
6
   Copyright (C) Tim Potter 2003
7
   Copyright (C) Andrew Tridgell 2003
8
   
9
   This program is free software; you can redistribute it and/or modify
10
   it under the terms of the GNU General Public License as published by
11
   the Free Software Foundation; either version 3 of the License, or
12
   (at your option) any later version.
13
   
14
   This program is distributed in the hope that it will be useful,
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
   
19
   You should have received a copy of the GNU General Public License
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
*/
22
23
#define SOURCE4_LIBRPC_INTERNALS 1
24
25
#include "includes.h"
26
#include "system/filesys.h"
27
#include <tevent.h>
28
#include "lib/tsocket/tsocket.h"
29
#include "libcli/smb/smb_constants.h"
30
#include "libcli/smb/smbXcli_base.h"
31
#include "libcli/smb/tstream_smbXcli_np.h"
32
#include "libcli/raw/libcliraw.h"
33
#include "libcli/smb2/smb2.h"
34
#include "librpc/rpc/dcerpc.h"
35
#include "librpc/rpc/dcerpc_proto.h"
36
#include "libcli/composite/composite.h"
37
38
#undef strncasecmp
39
40
/* transport private information used by SMB pipe transport */
41
struct smb_private {
42
  DATA_BLOB session_key;
43
44
  /*
45
   * these are needed to open a secondary connection
46
   */
47
  struct smbXcli_conn *conn;
48
  struct smbXcli_session *session;
49
  struct smbXcli_tcon *tcon;
50
  uint32_t timeout_msec;
51
};
52
53
/*
54
  fetch the user session key 
55
*/
56
static NTSTATUS smb_session_key(struct dcecli_connection *c, DATA_BLOB *session_key)
57
0
{
58
0
  struct smb_private *smb = talloc_get_type_abort(
59
0
    c->transport.private_data, struct smb_private);
60
61
0
  if (smb == NULL) return NT_STATUS_CONNECTION_DISCONNECTED;
62
63
0
  if (smb->session_key.length == 0) {
64
0
    return NT_STATUS_NO_USER_SESSION_KEY;
65
0
  }
66
67
0
  *session_key = smb->session_key;
68
0
  return NT_STATUS_OK;
69
0
}
70
71
struct dcerpc_pipe_open_smb_state {
72
  struct dcecli_connection *c;
73
  struct composite_context *ctx;
74
75
  const char *fname;
76
77
  struct smb_private *smb;
78
};
79
80
static void dcerpc_pipe_open_smb_done(struct tevent_req *subreq);
81
82
struct composite_context *dcerpc_pipe_open_smb_send(struct dcecli_connection *c,
83
            struct smbXcli_conn *conn,
84
            struct smbXcli_session *session,
85
            struct smbXcli_tcon *tcon,
86
            uint32_t timeout_msec,
87
            const char *pipe_name)
88
0
{
89
0
  struct composite_context *ctx;
90
0
  struct dcerpc_pipe_open_smb_state *state;
91
0
  uint16_t pid = 0;
92
0
  struct tevent_req *subreq;
93
94
0
  ctx = composite_create(c, c->event_ctx);
95
0
  if (ctx == NULL) return NULL;
96
97
0
  state = talloc(ctx, struct dcerpc_pipe_open_smb_state);
98
0
  if (composite_nomem(state, ctx)) return ctx;
99
0
  ctx->private_data = state;
100
101
0
  state->c = c;
102
0
  state->ctx = ctx;
103
104
0
  if ((strncasecmp(pipe_name, "/pipe/", 6) == 0) || 
105
0
      (strncasecmp(pipe_name, "\\pipe\\", 6) == 0)) {
106
0
    pipe_name += 6;
107
0
  }
108
0
  if ((strncasecmp(pipe_name, "/", 1) == 0) ||
109
0
      (strncasecmp(pipe_name, "\\", 1) == 0)) {
110
0
    pipe_name += 1;
111
0
  }
112
0
  state->fname = talloc_strdup(state, pipe_name);
113
0
  if (composite_nomem(state->fname, ctx)) return ctx;
114
115
0
  state->smb = talloc_zero(state, struct smb_private);
116
0
  if (composite_nomem(state->smb, ctx)) return ctx;
117
118
0
  state->smb->conn = conn;
119
0
  state->smb->session = session;
120
0
  state->smb->tcon = tcon;
121
0
  state->smb->timeout_msec = timeout_msec;
122
123
0
  state->c->server_name = strupper_talloc(state->c,
124
0
    smbXcli_conn_remote_name(conn));
125
0
  if (composite_nomem(state->c->server_name, ctx)) return ctx;
126
127
0
  ctx->status = smbXcli_session_application_key(session,
128
0
                  state->smb,
129
0
                  &state->smb->session_key);
130
0
  if (NT_STATUS_EQUAL(ctx->status, NT_STATUS_NO_USER_SESSION_KEY)) {
131
0
    state->smb->session_key = data_blob_null;
132
0
    ctx->status = NT_STATUS_OK;
133
0
  }
134
0
  if (!composite_is_ok(ctx)) return ctx;
135
136
0
  subreq = tstream_smbXcli_np_open_send(state, c->event_ctx,
137
0
                conn, session, tcon, pid,
138
0
                timeout_msec, state->fname);
139
0
  if (composite_nomem(subreq, ctx)) return ctx;
140
0
  tevent_req_set_callback(subreq, dcerpc_pipe_open_smb_done, state);
141
142
0
  return ctx;
143
0
}
144
145
static void dcerpc_pipe_open_smb_done(struct tevent_req *subreq)
146
0
{
147
0
  struct dcerpc_pipe_open_smb_state *state =
148
0
    tevent_req_callback_data(subreq,
149
0
    struct dcerpc_pipe_open_smb_state);
150
0
  struct composite_context *ctx = state->ctx;
151
0
  struct dcecli_connection *c = state->c;
152
0
  uint16_t enc_cipher;
153
154
0
  ctx->status = tstream_smbXcli_np_open_recv(subreq,
155
0
               state->smb,
156
0
               &state->c->transport.stream);
157
0
  TALLOC_FREE(subreq);
158
0
  if (!composite_is_ok(ctx)) return;
159
160
0
  state->c->transport.write_queue =
161
0
    tevent_queue_create(state->c, "dcerpc_smb write queue");
162
0
  if (composite_nomem(state->c->transport.write_queue, ctx)) return;
163
164
  /*
165
    fill in the transport methods
166
  */
167
0
  c->transport.transport       = NCACN_NP;
168
0
  c->transport.private_data    = NULL;
169
170
  /*
171
   * Windows uses 4280 for ncacn_np,
172
   * so we also use it, this is what our
173
   * tstream_smbXcli_np code relies on.
174
   */
175
0
  c->srv_max_xmit_frag = 4280;
176
0
  c->srv_max_recv_frag = 4280;
177
178
  /* Over-ride the default session key with the SMB session key */
179
0
  c->security_state.session_key = smb_session_key;
180
181
0
  enc_cipher = smb2cli_session_get_encryption_cipher(state->smb->session);
182
0
  switch (enc_cipher) {
183
0
  case SMB2_ENCRYPTION_AES128_CCM:
184
0
  case SMB2_ENCRYPTION_AES128_GCM:
185
0
    c->transport.encrypted = true;
186
0
    break;
187
0
  default:
188
0
    c->transport.encrypted = false;
189
0
  }
190
191
0
  c->transport.private_data = talloc_move(c, &state->smb);
192
193
0
  composite_done(ctx);
194
0
}
195
196
NTSTATUS dcerpc_pipe_open_smb_recv(struct composite_context *c)
197
0
{
198
0
  NTSTATUS status = composite_wait(c);
199
0
  talloc_free(c);
200
0
  return status;
201
0
}
202
203
_PUBLIC_ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe *p,
204
            struct smbcli_tree *t,
205
            const char *pipe_name)
206
0
{
207
0
  struct smbXcli_conn *conn;
208
0
  struct smbXcli_session *session;
209
0
  struct smbXcli_tcon *tcon;
210
0
  struct composite_context *ctx;
211
212
0
  conn = t->session->transport->conn;
213
0
  session = t->session->smbXcli;
214
0
  tcon = t->smbXcli;
215
0
  smb1cli_tcon_set_id(tcon, t->tid);
216
217
  /* if we don't have a binding on this pipe yet, then create one */
218
0
  if (p->binding == NULL) {
219
0
    struct dcerpc_binding *b;
220
0
    NTSTATUS status;
221
0
    const char *r = smbXcli_conn_remote_name(conn);
222
0
    char *str;
223
0
    SMB_ASSERT(r != NULL);
224
0
    str = talloc_asprintf(p, "ncacn_np:%s", r);
225
0
    if (str == NULL) {
226
0
      return NT_STATUS_NO_MEMORY;
227
0
    }
228
0
    status = dcerpc_parse_binding(p, str, &b);
229
0
    talloc_free(str);
230
0
    if (!NT_STATUS_IS_OK(status)) {
231
0
      return status;
232
0
    }
233
0
    p->binding = b;
234
0
  }
235
236
0
  ctx = dcerpc_pipe_open_smb_send(p->conn,
237
0
          conn, session, tcon,
238
0
          DCERPC_REQUEST_TIMEOUT * 1000,
239
0
          pipe_name);
240
0
  if (ctx == NULL) {
241
0
    return NT_STATUS_NO_MEMORY;
242
0
  }
243
244
0
  return dcerpc_pipe_open_smb_recv(ctx);
245
0
}
246
247
_PUBLIC_ NTSTATUS dcerpc_pipe_open_smb2(struct dcerpc_pipe *p,
248
            struct smb2_tree *t,
249
            const char *pipe_name)
250
0
{
251
0
  struct smbXcli_conn *conn;
252
0
  struct smbXcli_session *session;
253
0
  struct smbXcli_tcon *tcon;
254
0
  struct composite_context *ctx;
255
256
0
  conn = t->session->transport->conn;
257
0
  session = t->session->smbXcli;
258
0
  tcon = t->smbXcli;
259
260
  /* if we don't have a binding on this pipe yet, then create one */
261
0
  if (p->binding == NULL) {
262
0
    struct dcerpc_binding *b;
263
0
    NTSTATUS status;
264
0
    const char *r = smbXcli_conn_remote_name(conn);
265
0
    char *str;
266
0
    SMB_ASSERT(r != NULL);
267
0
    str = talloc_asprintf(p, "ncacn_np:%s", r);
268
0
    if (str == NULL) {
269
0
      return NT_STATUS_NO_MEMORY;
270
0
    }
271
0
    status = dcerpc_parse_binding(p, str, &b);
272
0
    talloc_free(str);
273
0
    if (!NT_STATUS_IS_OK(status)) {
274
0
      return status;
275
0
    }
276
0
    p->binding = b;
277
0
  }
278
279
0
  ctx = dcerpc_pipe_open_smb_send(p->conn,
280
0
          conn, session, tcon,
281
0
          DCERPC_REQUEST_TIMEOUT * 1000,
282
0
          pipe_name);
283
0
  if (ctx == NULL) {
284
0
    return NT_STATUS_NO_MEMORY;
285
0
  }
286
287
0
  return dcerpc_pipe_open_smb_recv(ctx);
288
0
}
289
290
struct composite_context *dcerpc_secondary_smb_send(struct dcecli_connection *c1,
291
                struct dcecli_connection *c2,
292
                const char *pipe_name)
293
0
{
294
0
  struct smb_private *smb;
295
296
0
  if (c1->transport.transport != NCACN_NP) return NULL;
297
298
0
  smb = talloc_get_type(c1->transport.private_data, struct smb_private);
299
0
  if (!smb) return NULL;
300
301
0
  return dcerpc_pipe_open_smb_send(c2,
302
0
           smb->conn,
303
0
           smb->session,
304
0
           smb->tcon,
305
0
           smb->timeout_msec,
306
0
           pipe_name);
307
0
}
308
309
NTSTATUS dcerpc_secondary_smb_recv(struct composite_context *c)
310
0
{
311
0
  return dcerpc_pipe_open_smb_recv(c);
312
0
}