2 Unix SMB/CIFS implementation.
4 dcerpc over SMB transport
6 Copyright (C) Tim Potter 2003
7 Copyright (C) Andrew Tridgell 2003
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 2 of the License, or
12 (at your option) any later version.
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.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "libcli/raw/libcliraw.h"
26 #include "libcli/composite/composite.h"
27 #include "librpc/rpc/dcerpc.h"
29 /* transport private information used by SMB pipe transport */
32 struct smbcli_tree
*tree
;
33 const char *server_name
;
38 tell the dcerpc layer that the transport is dead
40 static void pipe_dead(struct dcerpc_connection
*c
, NTSTATUS status
)
42 c
->transport
.recv_data(c
, NULL
, status
);
47 this holds the state of an in-flight call
49 struct smb_read_state
{
50 struct dcerpc_connection
*c
;
51 struct smbcli_request
*req
;
58 called when a read request has completed
60 static void smb_read_callback(struct smbcli_request
*req
)
62 struct smb_private
*smb
;
63 struct smb_read_state
*state
;
68 state
= talloc_get_type(req
->async
.private, struct smb_read_state
);
69 smb
= talloc_get_type(state
->c
->transport
.private, struct smb_private
);
72 status
= smb_raw_read_recv(state
->req
, io
);
73 if (NT_STATUS_IS_ERR(status
)) {
74 pipe_dead(state
->c
, status
);
79 state
->received
+= io
->readx
.out
.nread
;
81 if (state
->received
< 16) {
82 DEBUG(0,("dcerpc_smb: short packet (length %d) in read callback!\n",
83 (int)state
->received
));
84 pipe_dead(state
->c
, NT_STATUS_INFO_LENGTH_MISMATCH
);
89 frag_length
= dcerpc_get_frag_length(&state
->data
);
91 if (frag_length
<= state
->received
) {
92 DATA_BLOB data
= state
->data
;
93 struct dcerpc_connection
*c
= state
->c
;
94 data
.length
= state
->received
;
95 talloc_steal(state
->c
, data
.data
);
97 c
->transport
.recv_data(c
, &data
, NT_STATUS_OK
);
101 /* initiate another read request, as we only got part of a fragment */
102 state
->data
.data
= talloc_realloc(state
, state
->data
.data
, uint8_t, frag_length
);
104 io
->readx
.in
.mincnt
= MIN(state
->c
->srv_max_xmit_frag
,
105 frag_length
- state
->received
);
106 io
->readx
.in
.maxcnt
= io
->readx
.in
.mincnt
;
107 io
->readx
.out
.data
= state
->data
.data
+ state
->received
;
109 state
->req
= smb_raw_read_send(smb
->tree
, io
);
110 if (state
->req
== NULL
) {
111 pipe_dead(state
->c
, NT_STATUS_NO_MEMORY
);
116 state
->req
->async
.fn
= smb_read_callback
;
117 state
->req
->async
.private = state
;
121 trigger a read request from the server, possibly with some initial
122 data in the read buffer
124 static NTSTATUS
send_read_request_continue(struct dcerpc_connection
*c
, DATA_BLOB
*blob
)
126 struct smb_private
*smb
= c
->transport
.private;
128 struct smb_read_state
*state
;
129 struct smbcli_request
*req
;
131 state
= talloc(smb
, struct smb_read_state
);
133 return NT_STATUS_NO_MEMORY
;
139 state
->data
= data_blob_talloc(state
, NULL
, 0x2000);
141 uint32_t frag_length
= blob
->length
>=16?
142 dcerpc_get_frag_length(blob
):0x2000;
143 state
->received
= blob
->length
;
144 state
->data
= data_blob_talloc(state
, NULL
, frag_length
);
145 if (!state
->data
.data
) {
147 return NT_STATUS_NO_MEMORY
;
149 memcpy(state
->data
.data
, blob
->data
, blob
->length
);
152 state
->io
= talloc(state
, union smb_read
);
155 io
->generic
.level
= RAW_READ_READX
;
156 io
->readx
.in
.file
.fnum
= smb
->fnum
;
157 io
->readx
.in
.mincnt
= state
->data
.length
- state
->received
;
158 io
->readx
.in
.maxcnt
= io
->readx
.in
.mincnt
;
159 io
->readx
.in
.offset
= 0;
160 io
->readx
.in
.remaining
= 0;
161 io
->readx
.in
.read_for_execute
= False
;
162 io
->readx
.out
.data
= state
->data
.data
+ state
->received
;
163 req
= smb_raw_read_send(smb
->tree
, io
);
165 return NT_STATUS_NO_MEMORY
;
168 req
->async
.fn
= smb_read_callback
;
169 req
->async
.private = state
;
178 trigger a read request from the server
180 static NTSTATUS
send_read_request(struct dcerpc_connection
*c
)
182 return send_read_request_continue(c
, NULL
);
186 this holds the state of an in-flight trans call
188 struct smb_trans_state
{
189 struct dcerpc_connection
*c
;
190 struct smbcli_request
*req
;
191 struct smb_trans2
*trans
;
195 called when a trans request has completed
197 static void smb_trans_callback(struct smbcli_request
*req
)
199 struct smb_trans_state
*state
= req
->async
.private;
200 struct dcerpc_connection
*c
= state
->c
;
203 status
= smb_raw_trans_recv(req
, state
, state
->trans
);
205 if (NT_STATUS_IS_ERR(status
)) {
206 pipe_dead(c
, status
);
210 if (!NT_STATUS_EQUAL(status
, STATUS_BUFFER_OVERFLOW
)) {
211 DATA_BLOB data
= state
->trans
->out
.data
;
212 talloc_steal(c
, data
.data
);
214 c
->transport
.recv_data(c
, &data
, NT_STATUS_OK
);
218 /* there is more to receive - setup a readx */
219 send_read_request_continue(c
, &state
->trans
->out
.data
);
224 send a SMBtrans style request
226 static NTSTATUS
smb_send_trans_request(struct dcerpc_connection
*c
, DATA_BLOB
*blob
)
228 struct smb_private
*smb
= c
->transport
.private;
229 struct smb_trans2
*trans
;
231 struct smb_trans_state
*state
;
233 state
= talloc(smb
, struct smb_trans_state
);
235 return NT_STATUS_NO_MEMORY
;
239 state
->trans
= talloc(state
, struct smb_trans2
);
240 trans
= state
->trans
;
242 trans
->in
.data
= *blob
;
243 trans
->in
.params
= data_blob(NULL
, 0);
245 setup
[0] = TRANSACT_DCERPCCMD
;
246 setup
[1] = smb
->fnum
;
248 trans
->in
.max_param
= 0;
249 trans
->in
.max_data
= smb_raw_max_trans_data(smb
->tree
, 0);
250 trans
->in
.max_setup
= 0;
251 trans
->in
.setup_count
= 2;
253 trans
->in
.timeout
= 0;
254 trans
->in
.setup
= setup
;
255 trans
->in
.trans_name
= "\\PIPE\\";
257 state
->req
= smb_raw_trans_send(smb
->tree
, trans
);
258 if (state
->req
== NULL
) {
260 return NT_STATUS_NO_MEMORY
;
263 state
->req
->async
.fn
= smb_trans_callback
;
264 state
->req
->async
.private = state
;
266 talloc_steal(state
, state
->req
);
272 called when a write request has completed
274 static void smb_write_callback(struct smbcli_request
*req
)
276 struct dcerpc_connection
*c
= req
->async
.private;
278 if (!NT_STATUS_IS_OK(req
->status
)) {
279 DEBUG(0,("dcerpc_smb: write callback error\n"));
280 pipe_dead(c
, req
->status
);
283 smbcli_request_destroy(req
);
287 send a packet to the server
289 static NTSTATUS
smb_send_request(struct dcerpc_connection
*c
, DATA_BLOB
*blob
, BOOL trigger_read
)
291 struct smb_private
*smb
= c
->transport
.private;
293 struct smbcli_request
*req
;
296 return smb_send_trans_request(c
, blob
);
299 io
.generic
.level
= RAW_WRITE_WRITEX
;
300 io
.writex
.in
.file
.fnum
= smb
->fnum
;
301 io
.writex
.in
.offset
= 0;
302 io
.writex
.in
.wmode
= PIPE_START_MESSAGE
;
303 io
.writex
.in
.remaining
= blob
->length
;
304 io
.writex
.in
.count
= blob
->length
;
305 io
.writex
.in
.data
= blob
->data
;
307 /* we must not timeout at the smb level for rpc requests, as otherwise
308 signing/sealing can be messed up */
309 smb
->tree
->session
->transport
->options
.request_timeout
= 0;
311 req
= smb_raw_write_send(smb
->tree
, &io
);
313 return NT_STATUS_NO_MEMORY
;
316 req
->async
.fn
= smb_write_callback
;
317 req
->async
.private = c
;
320 send_read_request(c
);
327 shutdown SMB pipe connection
329 static NTSTATUS
smb_shutdown_pipe(struct dcerpc_connection
*c
)
331 struct smb_private
*smb
= c
->transport
.private;
333 struct smbcli_request
*req
;
335 /* maybe we're still starting up */
336 if (!smb
) return NT_STATUS_OK
;
338 io
.close
.level
= RAW_CLOSE_CLOSE
;
339 io
.close
.in
.file
.fnum
= smb
->fnum
;
340 io
.close
.in
.write_time
= 0;
341 req
= smb_raw_close_send(smb
->tree
, &io
);
343 /* we don't care if this fails, so just free it if it succeeds */
344 req
->async
.fn
= (void (*)(struct smbcli_request
*))talloc_free
;
353 return SMB server name (called name)
355 static const char *smb_peer_name(struct dcerpc_connection
*c
)
357 struct smb_private
*smb
= c
->transport
.private;
358 return smb
->server_name
;
362 return remote name we make the actual connection (good for kerberos)
364 static const char *smb_target_hostname(struct dcerpc_connection
*c
)
366 struct smb_private
*smb
= talloc_get_type(c
->transport
.private, struct smb_private
);
367 return smb
->tree
->session
->transport
->socket
->hostname
;
371 fetch the user session key
373 static NTSTATUS
smb_session_key(struct dcerpc_connection
*c
, DATA_BLOB
*session_key
)
375 struct smb_private
*smb
= c
->transport
.private;
377 if (smb
->tree
->session
->user_session_key
.data
) {
378 *session_key
= smb
->tree
->session
->user_session_key
;
381 return NT_STATUS_NO_USER_SESSION_KEY
;
384 struct pipe_open_smb_state
{
385 union smb_open
*open
;
386 struct dcerpc_connection
*c
;
387 struct smbcli_tree
*tree
;
388 struct composite_context
*ctx
;
391 static void pipe_open_recv(struct smbcli_request
*req
);
393 struct composite_context
*dcerpc_pipe_open_smb_send(struct dcerpc_pipe
*p
,
394 struct smbcli_tree
*tree
,
395 const char *pipe_name
)
397 struct composite_context
*ctx
;
398 struct pipe_open_smb_state
*state
;
399 struct smbcli_request
*req
;
400 struct dcerpc_connection
*c
= p
->conn
;
402 /* if we don't have a binding on this pipe yet, then create one */
403 if (p
->binding
== NULL
) {
405 char *s
= talloc_asprintf(p
, "ncacn_np:%s", tree
->session
->transport
->socket
->hostname
);
406 if (s
== NULL
) return NULL
;
407 status
= dcerpc_parse_binding(p
, s
, &p
->binding
);
409 if (!NT_STATUS_IS_OK(status
)) {
414 ctx
= composite_create(c
, c
->event_ctx
);
415 if (ctx
== NULL
) return NULL
;
417 state
= talloc(ctx
, struct pipe_open_smb_state
);
418 if (composite_nomem(state
, ctx
)) return ctx
;
419 ctx
->private_data
= state
;
425 state
->open
= talloc(state
, union smb_open
);
426 if (composite_nomem(state
->open
, ctx
)) return ctx
;
428 state
->open
->ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
429 state
->open
->ntcreatex
.in
.flags
= 0;
430 state
->open
->ntcreatex
.in
.root_fid
= 0;
431 state
->open
->ntcreatex
.in
.access_mask
=
432 SEC_STD_READ_CONTROL
|
433 SEC_FILE_WRITE_ATTRIBUTE
|
437 state
->open
->ntcreatex
.in
.file_attr
= 0;
438 state
->open
->ntcreatex
.in
.alloc_size
= 0;
439 state
->open
->ntcreatex
.in
.share_access
=
440 NTCREATEX_SHARE_ACCESS_READ
|
441 NTCREATEX_SHARE_ACCESS_WRITE
;
442 state
->open
->ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
443 state
->open
->ntcreatex
.in
.create_options
= 0;
444 state
->open
->ntcreatex
.in
.impersonation
=
445 NTCREATEX_IMPERSONATION_IMPERSONATION
;
446 state
->open
->ntcreatex
.in
.security_flags
= 0;
448 if ((strncasecmp(pipe_name
, "/pipe/", 6) == 0) ||
449 (strncasecmp(pipe_name
, "\\pipe\\", 6) == 0)) {
452 state
->open
->ntcreatex
.in
.fname
=
453 (pipe_name
[0] == '\\') ?
454 talloc_strdup(state
->open
, pipe_name
) :
455 talloc_asprintf(state
->open
, "\\%s", pipe_name
);
456 if (composite_nomem(state
->open
->ntcreatex
.in
.fname
, ctx
)) return ctx
;
458 req
= smb_raw_open_send(tree
, state
->open
);
459 composite_continue_smb(ctx
, req
, pipe_open_recv
, state
);
463 static void pipe_open_recv(struct smbcli_request
*req
)
465 struct pipe_open_smb_state
*state
= talloc_get_type(req
->async
.private,
466 struct pipe_open_smb_state
);
467 struct composite_context
*ctx
= state
->ctx
;
468 struct dcerpc_connection
*c
= state
->c
;
469 struct smb_private
*smb
;
471 ctx
->status
= smb_raw_open_recv(req
, state
, state
->open
);
472 if (!composite_is_ok(ctx
)) return;
475 fill in the transport methods
477 c
->transport
.transport
= NCACN_NP
;
478 c
->transport
.private = NULL
;
479 c
->transport
.shutdown_pipe
= smb_shutdown_pipe
;
480 c
->transport
.peer_name
= smb_peer_name
;
481 c
->transport
.target_hostname
= smb_target_hostname
;
483 c
->transport
.send_request
= smb_send_request
;
484 c
->transport
.send_read
= send_read_request
;
485 c
->transport
.recv_data
= NULL
;
487 /* Over-ride the default session key with the SMB session key */
488 c
->security_state
.session_key
= smb_session_key
;
490 smb
= talloc(c
, struct smb_private
);
491 if (composite_nomem(smb
, ctx
)) return;
493 smb
->fnum
= state
->open
->ntcreatex
.out
.file
.fnum
;
494 smb
->tree
= talloc_reference(smb
, state
->tree
);
495 smb
->server_name
= strupper_talloc(smb
,
496 state
->tree
->session
->transport
->called
.name
);
497 if (composite_nomem(smb
->server_name
, ctx
)) return;
498 c
->transport
.private = smb
;
503 NTSTATUS
dcerpc_pipe_open_smb_recv(struct composite_context
*c
)
505 NTSTATUS status
= composite_wait(c
);
510 NTSTATUS
dcerpc_pipe_open_smb(struct dcerpc_pipe
*p
,
511 struct smbcli_tree
*tree
,
512 const char *pipe_name
)
514 struct composite_context
*ctx
= dcerpc_pipe_open_smb_send(p
, tree
,
516 return dcerpc_pipe_open_smb_recv(ctx
);
520 return the SMB tree used for a dcerpc over SMB pipe
522 struct smbcli_tree
*dcerpc_smb_tree(struct dcerpc_connection
*c
)
524 struct smb_private
*smb
;
526 if (c
->transport
.transport
!= NCACN_NP
) return NULL
;
528 smb
= talloc_get_type(c
->transport
.private, struct smb_private
);
529 if (!smb
) return NULL
;