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 3 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, see <http://www.gnu.org/licenses/>.
24 #include "system/filesys.h"
26 #include "lib/tsocket/tsocket.h"
27 #include "libcli/smb/smb_constants.h"
28 #include "libcli/smb/smbXcli_base.h"
29 #include "libcli/smb/tstream_smbXcli_np.h"
30 #include "libcli/raw/libcliraw.h"
31 #include "libcli/smb2/smb2.h"
32 #include "librpc/rpc/dcerpc.h"
33 #include "librpc/rpc/dcerpc_proto.h"
34 #include "libcli/composite/composite.h"
36 /* transport private information used by SMB pipe transport */
38 DATA_BLOB session_key;
41 * these are needed to open a secondary connection
43 struct smbXcli_conn *conn;
44 struct smbXcli_session *session;
45 struct smbXcli_tcon *tcon;
46 uint32_t timeout_msec;
51 Tell the dcerpc layer that the transport is dead.
52 This function is declared here because it is going to be private.
54 void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status);
56 struct smb_send_read_state {
57 struct dcecli_connection *p;
60 static int smb_send_read_state_destructor(struct smb_send_read_state *state)
62 struct dcecli_connection *p = state->p;
64 p->transport.read_subreq = NULL;
69 static void smb_send_read_done(struct tevent_req *subreq);
71 static NTSTATUS smb_send_read(struct dcecli_connection *p)
73 struct smb_private *sock = talloc_get_type_abort(
74 p->transport.private_data, struct smb_private);
75 struct smb_send_read_state *state;
77 if (p->transport.read_subreq != NULL) {
78 p->transport.pending_reads++;
82 state = talloc_zero(sock, struct smb_send_read_state);
84 return NT_STATUS_NO_MEMORY;
88 talloc_set_destructor(state, smb_send_read_state_destructor);
90 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
93 if (p->transport.read_subreq == NULL) {
94 return NT_STATUS_NO_MEMORY;
96 tevent_req_set_callback(p->transport.read_subreq, smb_send_read_done, state);
101 static void smb_send_read_done(struct tevent_req *subreq)
103 struct smb_send_read_state *state =
104 tevent_req_callback_data(subreq,
105 struct smb_send_read_state);
106 struct dcecli_connection *p = state->p;
108 struct ncacn_packet *pkt;
111 status = dcerpc_read_ncacn_packet_recv(subreq, state,
114 if (!NT_STATUS_IS_OK(status)) {
116 dcerpc_transport_dead(p, status);
121 * here we steal into thet connection context,
122 * but p->transport.recv_data() will steal or free it again
124 talloc_steal(p, blob.data);
127 if (p->transport.pending_reads > 0) {
128 p->transport.pending_reads--;
130 status = smb_send_read(p);
131 if (!NT_STATUS_IS_OK(status)) {
132 dcerpc_transport_dead(p, status);
137 if (p->transport.recv_data) {
138 p->transport.recv_data(p, &blob, NT_STATUS_OK);
143 send an initial pdu in a multi-pdu sequence
146 struct smb_send_request_state {
147 struct dcecli_connection *p;
152 static int smb_send_request_state_destructor(struct smb_send_request_state *state)
154 state->p->transport.read_subreq = NULL;
159 static void smb_send_request_wait_done(struct tevent_req *subreq);
160 static void smb_send_request_done(struct tevent_req *subreq);
162 static NTSTATUS smb_send_request(struct dcecli_connection *p, DATA_BLOB *data,
165 struct smb_private *sock = talloc_get_type_abort(
166 p->transport.private_data, struct smb_private);
167 struct smb_send_request_state *state;
168 struct tevent_req *subreq;
169 bool use_trans = trigger_read;
171 if (p->transport.stream == NULL) {
172 return NT_STATUS_CONNECTION_DISCONNECTED;
175 state = talloc_zero(sock, struct smb_send_request_state);
177 return NT_STATUS_NO_MEMORY;
181 state->blob = data_blob_talloc(state, data->data, data->length);
182 if (state->blob.data == NULL) {
184 return NT_STATUS_NO_MEMORY;
186 state->iov.iov_base = (void *)state->blob.data;
187 state->iov.iov_len = state->blob.length;
189 if (p->transport.read_subreq != NULL) {
195 * we need to block reads until our write is
196 * the next in the write queue.
198 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
199 p->transport.write_queue);
200 if (p->transport.read_subreq == NULL) {
202 return NT_STATUS_NO_MEMORY;
204 tevent_req_set_callback(p->transport.read_subreq,
205 smb_send_request_wait_done,
208 talloc_set_destructor(state, smb_send_request_state_destructor);
210 trigger_read = false;
213 subreq = tstream_writev_queue_send(state, p->event_ctx,
215 p->transport.write_queue,
217 if (subreq == NULL) {
219 return NT_STATUS_NO_MEMORY;
221 tevent_req_set_callback(subreq, smb_send_request_done, state);
230 static void smb_send_request_wait_done(struct tevent_req *subreq)
232 struct smb_send_request_state *state =
233 tevent_req_callback_data(subreq,
234 struct smb_send_request_state);
235 struct dcecli_connection *p = state->p;
239 p->transport.read_subreq = NULL;
240 talloc_set_destructor(state, NULL);
242 ok = tevent_queue_wait_recv(subreq);
245 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
249 if (tevent_queue_length(p->transport.write_queue) <= 2) {
250 status = tstream_smbXcli_np_use_trans(p->transport.stream);
251 if (!NT_STATUS_IS_OK(status)) {
253 dcerpc_transport_dead(p, status);
258 /* we free subreq after tstream_smbXcli_np_use_trans */
264 static void smb_send_request_done(struct tevent_req *subreq)
266 struct smb_send_request_state *state =
267 tevent_req_callback_data(subreq,
268 struct smb_send_request_state);
272 ret = tstream_writev_queue_recv(subreq, &error);
275 struct dcecli_connection *p = state->p;
276 NTSTATUS status = map_nt_error_from_unix_common(error);
279 dcerpc_transport_dead(p, status);
287 shutdown SMB pipe connection
289 struct smb_shutdown_pipe_state {
290 struct dcecli_connection *c;
294 static void smb_shutdown_pipe_done(struct tevent_req *subreq);
296 static NTSTATUS smb_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
298 struct smb_private *smb = talloc_get_type_abort(
299 c->transport.private_data, struct smb_private);
300 struct smb_shutdown_pipe_state *state;
301 struct tevent_req *subreq;
303 if (c->transport.stream == NULL) {
307 state = talloc_zero(smb, struct smb_shutdown_pipe_state);
309 return NT_STATUS_NO_MEMORY;
312 state->status = status;
314 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
315 if (subreq == NULL) {
316 return NT_STATUS_NO_MEMORY;
318 tevent_req_set_callback(subreq, smb_shutdown_pipe_done, state);
323 static void smb_shutdown_pipe_done(struct tevent_req *subreq)
325 struct smb_shutdown_pipe_state *state =
326 tevent_req_callback_data(subreq, struct smb_shutdown_pipe_state);
327 struct dcecli_connection *c = state->c;
328 NTSTATUS status = state->status;
332 * here we ignore the return values...
334 tstream_disconnect_recv(subreq, &error);
339 dcerpc_transport_dead(c, status);
343 fetch the user session key
345 static NTSTATUS smb_session_key(struct dcecli_connection *c, DATA_BLOB *session_key)
347 struct smb_private *smb = talloc_get_type_abort(
348 c->transport.private_data, struct smb_private);
350 if (smb == NULL) return NT_STATUS_CONNECTION_DISCONNECTED;
352 if (smb->session_key.length == 0) {
353 return NT_STATUS_NO_USER_SESSION_KEY;
356 *session_key = smb->session_key;
360 struct dcerpc_pipe_open_smb_state {
361 struct dcecli_connection *c;
362 struct composite_context *ctx;
366 struct smb_private *smb;
369 static void dcerpc_pipe_open_smb_done(struct tevent_req *subreq);
371 struct composite_context *dcerpc_pipe_open_smb_send(struct dcecli_connection *c,
372 struct smbXcli_conn *conn,
373 struct smbXcli_session *session,
374 struct smbXcli_tcon *tcon,
375 uint32_t timeout_msec,
376 const char *pipe_name)
378 struct composite_context *ctx;
379 struct dcerpc_pipe_open_smb_state *state;
381 struct tevent_req *subreq;
383 ctx = composite_create(c, c->event_ctx);
384 if (ctx == NULL) return NULL;
386 state = talloc(ctx, struct dcerpc_pipe_open_smb_state);
387 if (composite_nomem(state, ctx)) return ctx;
388 ctx->private_data = state;
393 if ((strncasecmp(pipe_name, "/pipe/", 6) == 0) ||
394 (strncasecmp(pipe_name, "\\pipe\\", 6) == 0)) {
397 if ((strncasecmp(pipe_name, "/", 1) == 0) ||
398 (strncasecmp(pipe_name, "\\", 1) == 0)) {
401 state->fname = talloc_strdup(state, pipe_name);
402 if (composite_nomem(state->fname, ctx)) return ctx;
404 state->smb = talloc_zero(state, struct smb_private);
405 if (composite_nomem(state->smb, ctx)) return ctx;
407 state->smb->conn = conn;
408 state->smb->session = session;
409 state->smb->tcon = tcon;
410 state->smb->timeout_msec = timeout_msec;
412 state->c->server_name = strupper_talloc(state->c,
413 smbXcli_conn_remote_name(conn));
414 if (composite_nomem(state->c->server_name, ctx)) return ctx;
416 ctx->status = smbXcli_session_application_key(session,
418 &state->smb->session_key);
419 if (NT_STATUS_EQUAL(ctx->status, NT_STATUS_NO_USER_SESSION_KEY)) {
420 state->smb->session_key = data_blob_null;
421 ctx->status = NT_STATUS_OK;
423 if (!composite_is_ok(ctx)) return ctx;
425 subreq = tstream_smbXcli_np_open_send(state, c->event_ctx,
426 conn, session, tcon, pid,
427 timeout_msec, state->fname);
428 if (composite_nomem(subreq, ctx)) return ctx;
429 tevent_req_set_callback(subreq, dcerpc_pipe_open_smb_done, state);
434 static void dcerpc_pipe_open_smb_done(struct tevent_req *subreq)
436 struct dcerpc_pipe_open_smb_state *state =
437 tevent_req_callback_data(subreq,
438 struct dcerpc_pipe_open_smb_state);
439 struct composite_context *ctx = state->ctx;
440 struct dcecli_connection *c = state->c;
442 ctx->status = tstream_smbXcli_np_open_recv(subreq,
444 &state->c->transport.stream);
446 if (!composite_is_ok(ctx)) return;
448 state->c->transport.write_queue =
449 tevent_queue_create(state->c, "dcerpc_smb write queue");
450 if (composite_nomem(state->c->transport.write_queue, ctx)) return;
453 fill in the transport methods
455 c->transport.transport = NCACN_NP;
456 c->transport.private_data = NULL;
457 c->transport.shutdown_pipe = smb_shutdown_pipe;
459 c->transport.send_request = smb_send_request;
460 c->transport.send_read = smb_send_read;
461 c->transport.recv_data = NULL;
464 * Windows uses 4280 for ncacn_np,
465 * so we also use it, this is what our
466 * tstream_smbXcli_np code relies on.
468 c->srv_max_xmit_frag = 4280;
469 c->srv_max_recv_frag = 4280;
471 /* Over-ride the default session key with the SMB session key */
472 c->security_state.session_key = smb_session_key;
474 c->transport.private_data = talloc_move(c, &state->smb);
479 NTSTATUS dcerpc_pipe_open_smb_recv(struct composite_context *c)
481 NTSTATUS status = composite_wait(c);
486 _PUBLIC_ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe *p,
487 struct smbcli_tree *t,
488 const char *pipe_name)
490 struct smbXcli_conn *conn;
491 struct smbXcli_session *session;
492 struct smbXcli_tcon *tcon;
493 uint32_t timeout_msec;
494 struct composite_context *ctx;
496 conn = t->session->transport->conn;
497 session = t->session->smbXcli;
499 smb1cli_tcon_set_id(tcon, t->tid);
500 timeout_msec = t->session->transport->options.request_timeout * 1000;
502 /* if we don't have a binding on this pipe yet, then create one */
503 if (p->binding == NULL) {
505 const char *r = smbXcli_conn_remote_name(conn);
507 SMB_ASSERT(r != NULL);
508 str = talloc_asprintf(p, "ncacn_np:%s", r);
510 return NT_STATUS_NO_MEMORY;
512 status = dcerpc_parse_binding(p, str,
515 if (!NT_STATUS_IS_OK(status)) {
520 ctx = dcerpc_pipe_open_smb_send(p->conn,
525 return NT_STATUS_NO_MEMORY;
528 return dcerpc_pipe_open_smb_recv(ctx);
531 _PUBLIC_ NTSTATUS dcerpc_pipe_open_smb2(struct dcerpc_pipe *p,
533 const char *pipe_name)
535 struct smbXcli_conn *conn;
536 struct smbXcli_session *session;
537 struct smbXcli_tcon *tcon;
538 uint32_t timeout_msec;
539 struct composite_context *ctx;
541 conn = t->session->transport->conn;
542 session = t->session->smbXcli;
544 timeout_msec = t->session->transport->options.request_timeout * 1000;
546 /* if we don't have a binding on this pipe yet, then create one */
547 if (p->binding == NULL) {
549 const char *r = smbXcli_conn_remote_name(conn);
551 SMB_ASSERT(r != NULL);
552 str = talloc_asprintf(p, "ncacn_np:%s", r);
554 return NT_STATUS_NO_MEMORY;
556 status = dcerpc_parse_binding(p, str,
559 if (!NT_STATUS_IS_OK(status)) {
564 ctx = dcerpc_pipe_open_smb_send(p->conn,
569 return NT_STATUS_NO_MEMORY;
572 return dcerpc_pipe_open_smb_recv(ctx);
575 struct composite_context *dcerpc_secondary_smb_send(struct dcecli_connection *c1,
576 struct dcecli_connection *c2,
577 const char *pipe_name)
579 struct smb_private *smb;
581 if (c1->transport.transport != NCACN_NP) return NULL;
583 smb = talloc_get_type(c1->transport.private_data, struct smb_private);
584 if (!smb) return NULL;
586 return dcerpc_pipe_open_smb_send(c2,
594 NTSTATUS dcerpc_secondary_smb_recv(struct composite_context *c)
596 return dcerpc_pipe_open_smb_recv(c);