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 "librpc/gen_ndr/ndr_security.h"
28 /* transport private information used by SMB pipe transport */
31 struct smbcli_tree *tree;
36 tell the dcerpc layer that the transport is dead
38 static void pipe_dead(struct dcerpc_connection *c, NTSTATUS status)
40 c->transport.recv_data(c, NULL, status);
45 this holds the state of an in-flight call
47 struct smb_read_state {
48 struct dcerpc_connection *c;
49 struct smbcli_request *req;
56 called when a read request has completed
58 static void smb_read_callback(struct smbcli_request *req)
60 struct smb_private *smb;
61 struct smb_read_state *state;
66 state = req->async.private;
67 smb = state->c->transport.private;
70 status = smb_raw_read_recv(state->req, io);
71 if (NT_STATUS_IS_ERR(status)) {
72 pipe_dead(state->c, status);
77 state->received += io->readx.out.nread;
79 if (state->received < 16) {
80 DEBUG(0,("dcerpc_smb: short packet (length %d) in read callback!\n",
82 pipe_dead(state->c, NT_STATUS_INFO_LENGTH_MISMATCH);
87 frag_length = dcerpc_get_frag_length(&state->data);
89 if (frag_length <= state->received) {
90 state->data.length = state->received;
91 state->c->transport.recv_data(state->c, &state->data, NT_STATUS_OK);
96 /* initiate another read request, as we only got part of a fragment */
97 state->data.data = talloc_realloc(state, state->data.data, uint8_t, frag_length);
99 io->readx.in.mincnt = MIN(state->c->srv_max_xmit_frag,
100 frag_length - state->received);
101 io->readx.in.maxcnt = io->readx.in.mincnt;
102 io->readx.out.data = state->data.data + state->received;
104 state->req = smb_raw_read_send(smb->tree, io);
105 if (state->req == NULL) {
106 pipe_dead(state->c, NT_STATUS_NO_MEMORY);
111 state->req->async.fn = smb_read_callback;
112 state->req->async.private = state;
116 trigger a read request from the server, possibly with some initial
117 data in the read buffer
119 static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLOB *blob)
121 struct smb_private *smb = c->transport.private;
123 struct smb_read_state *state;
124 struct smbcli_request *req;
126 state = talloc(smb, struct smb_read_state);
128 return NT_STATUS_NO_MEMORY;
134 state->data = data_blob_talloc(state, NULL, 0x2000);
136 uint32_t frag_length = blob->length>=16?
137 dcerpc_get_frag_length(blob):0x2000;
138 state->received = blob->length;
139 state->data = data_blob_talloc(state, NULL, frag_length);
140 if (!state->data.data) {
142 return NT_STATUS_NO_MEMORY;
144 memcpy(state->data.data, blob->data, blob->length);
147 state->io = talloc(state, union smb_read);
150 io->generic.level = RAW_READ_READX;
151 io->readx.in.fnum = smb->fnum;
152 io->readx.in.mincnt = state->data.length - state->received;
153 io->readx.in.maxcnt = io->readx.in.mincnt;
154 io->readx.in.offset = 0;
155 io->readx.in.remaining = 0;
156 io->readx.out.data = state->data.data + state->received;
157 req = smb_raw_read_send(smb->tree, io);
159 return NT_STATUS_NO_MEMORY;
162 req->async.fn = smb_read_callback;
163 req->async.private = state;
172 trigger a read request from the server
174 static NTSTATUS send_read_request(struct dcerpc_connection *c)
176 return send_read_request_continue(c, NULL);
180 this holds the state of an in-flight trans call
182 struct smb_trans_state {
183 struct dcerpc_connection *c;
184 struct smbcli_request *req;
185 struct smb_trans2 *trans;
189 called when a trans request has completed
191 static void smb_trans_callback(struct smbcli_request *req)
193 struct smb_trans_state *state = req->async.private;
194 struct dcerpc_connection *c = state->c;
197 status = smb_raw_trans_recv(req, state, state->trans);
199 if (NT_STATUS_IS_ERR(status)) {
200 pipe_dead(c, status);
204 if (!NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
205 c->transport.recv_data(c, &state->trans->out.data, NT_STATUS_OK);
210 /* there is more to receive - setup a readx */
211 send_read_request_continue(c, &state->trans->out.data);
216 send a SMBtrans style request
218 static NTSTATUS smb_send_trans_request(struct dcerpc_connection *c, DATA_BLOB *blob)
220 struct smb_private *smb = c->transport.private;
221 struct smb_trans2 *trans;
223 struct smb_trans_state *state;
225 state = talloc(smb, struct smb_trans_state);
227 return NT_STATUS_NO_MEMORY;
231 state->trans = talloc(state, struct smb_trans2);
232 trans = state->trans;
234 trans->in.data = *blob;
235 trans->in.params = data_blob(NULL, 0);
237 setup[0] = TRANSACT_DCERPCCMD;
238 setup[1] = smb->fnum;
240 trans->in.max_param = 0;
241 trans->in.max_data = smb_raw_max_trans_data(smb->tree, 0);
242 trans->in.max_setup = 0;
243 trans->in.setup_count = 2;
245 trans->in.timeout = 0;
246 trans->in.setup = setup;
247 trans->in.trans_name = "\\PIPE\\";
249 state->req = smb_raw_trans_send(smb->tree, trans);
250 if (state->req == NULL) {
252 return NT_STATUS_NO_MEMORY;
255 state->req->async.fn = smb_trans_callback;
256 state->req->async.private = state;
262 called when a write request has completed
264 static void smb_write_callback(struct smbcli_request *req)
266 struct dcerpc_connection *c = req->async.private;
268 if (!NT_STATUS_IS_OK(req->status)) {
269 DEBUG(0,("dcerpc_smb: write callback error\n"));
270 pipe_dead(c, req->status);
273 smbcli_request_destroy(req);
277 send a packet to the server
279 static NTSTATUS smb_send_request(struct dcerpc_connection *c, DATA_BLOB *blob, BOOL trigger_read)
281 struct smb_private *smb = c->transport.private;
283 struct smbcli_request *req;
286 return smb_send_trans_request(c, blob);
289 io.generic.level = RAW_WRITE_WRITEX;
290 io.writex.in.fnum = smb->fnum;
291 io.writex.in.offset = 0;
292 io.writex.in.wmode = PIPE_START_MESSAGE;
293 io.writex.in.remaining = blob->length;
294 io.writex.in.count = blob->length;
295 io.writex.in.data = blob->data;
297 req = smb_raw_write_send(smb->tree, &io);
299 return NT_STATUS_NO_MEMORY;
302 req->async.fn = smb_write_callback;
303 req->async.private = c;
306 send_read_request(c);
313 return the event context for the pipe, so the caller can wait
314 for events asynchronously
316 static struct event_context *smb_event_context(struct dcerpc_connection *c)
318 struct smb_private *smb = c->transport.private;
320 return smb->tree->session->transport->socket->event.ctx;
325 shutdown SMB pipe connection
327 static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c)
329 struct smb_private *smb = c->transport.private;
332 /* maybe we're still starting up */
333 if (!smb) return NT_STATUS_OK;
335 io.close.level = RAW_CLOSE_CLOSE;
336 io.close.in.fnum = smb->fnum;
337 io.close.in.write_time = 0;
338 smb_raw_close(smb->tree, &io);
346 return SMB server name
348 static const char *smb_peer_name(struct dcerpc_connection *c)
350 struct smb_private *smb = c->transport.private;
351 return smb->tree->session->transport->called.name;
355 fetch the user session key
357 static NTSTATUS smb_session_key(struct dcerpc_connection *c, DATA_BLOB *session_key)
359 struct smb_private *smb = c->transport.private;
361 if (smb->tree->session->user_session_key.data) {
362 *session_key = smb->tree->session->user_session_key;
365 return NT_STATUS_NO_USER_SESSION_KEY;
369 open a rpc connection to a named pipe
371 NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_connection *c,
372 struct smbcli_tree *tree,
373 const char *pipe_name)
375 struct smb_private *smb;
379 io.ntcreatex.level = RAW_OPEN_NTCREATEX;
380 io.ntcreatex.in.flags = 0;
381 io.ntcreatex.in.root_fid = 0;
382 io.ntcreatex.in.access_mask =
383 SEC_STD_READ_CONTROL |
384 SEC_FILE_WRITE_ATTRIBUTE |
388 io.ntcreatex.in.file_attr = 0;
389 io.ntcreatex.in.alloc_size = 0;
390 io.ntcreatex.in.share_access =
391 NTCREATEX_SHARE_ACCESS_READ |
392 NTCREATEX_SHARE_ACCESS_WRITE;
393 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
394 io.ntcreatex.in.create_options = 0;
395 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
396 io.ntcreatex.in.security_flags = 0;
397 io.ntcreatex.in.fname = pipe_name;
399 status = smb_raw_open(tree, tree, &io);
401 if (!NT_STATUS_IS_OK(status)) {
406 fill in the transport methods
408 c->transport.transport = NCACN_NP;
409 c->transport.private = NULL;
410 c->transport.shutdown_pipe = smb_shutdown_pipe;
411 c->transport.peer_name = smb_peer_name;
413 c->transport.send_request = smb_send_request;
414 c->transport.send_read = send_read_request;
415 c->transport.event_context = smb_event_context;
416 c->transport.recv_data = NULL;
418 /* Over-ride the default session key with the SMB session key */
419 c->security_state.session_key = smb_session_key;
421 smb = talloc(c, struct smb_private);
423 return NT_STATUS_NO_MEMORY;
426 smb->fnum = io.ntcreatex.out.fnum;
429 c->transport.private = smb;
435 return the SMB tree used for a dcerpc over SMB pipe
437 struct smbcli_tree *dcerpc_smb_tree(struct dcerpc_connection *c)
439 struct smb_private *smb = c->transport.private;
441 if (c->transport.transport != NCACN_NP) {