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.
26 /* transport private information used by SMB pipe transport */
29 struct smbcli_tree *tree;
34 tell the dcerpc layer that the transport is dead
36 static void pipe_dead(struct dcerpc_pipe *p, NTSTATUS status)
38 p->transport.recv_data(p, NULL, status);
43 this holds the state of an in-flight call
45 struct smb_read_state {
46 struct dcerpc_pipe *p;
47 struct smbcli_request *req;
54 called when a read request has completed
56 static void smb_read_callback(struct smbcli_request *req)
58 struct smb_private *smb;
59 struct smb_read_state *state;
64 state = req->async.private;
65 smb = state->p->transport.private;
68 status = smb_raw_read_recv(state->req, io);
69 if (NT_STATUS_IS_ERR(status)) {
70 pipe_dead(state->p, status);
75 state->received += io->readx.out.nread;
77 if (state->received < 16) {
78 DEBUG(0,("dcerpc_smb: short packet (length %d) in read callback!\n",
80 pipe_dead(state->p, NT_STATUS_INFO_LENGTH_MISMATCH);
85 frag_length = dcerpc_get_frag_length(&state->data);
87 if (frag_length <= state->received) {
88 state->data.length = state->received;
89 state->p->transport.recv_data(state->p, &state->data, NT_STATUS_OK);
94 /* initiate another read request, as we only got part of a fragment */
95 state->data.data = talloc_realloc(state->data.data, frag_length);
97 io->readx.in.mincnt = MIN(state->p->srv_max_xmit_frag,
98 frag_length - state->received);
99 io->readx.in.maxcnt = io->readx.in.mincnt;
100 io->readx.out.data = state->data.data + state->received;
102 state->req = smb_raw_read_send(smb->tree, io);
103 if (state->req == NULL) {
104 pipe_dead(state->p, NT_STATUS_NO_MEMORY);
109 state->req->async.fn = smb_read_callback;
110 state->req->async.private = state;
114 trigger a read request from the server, possibly with some initial
115 data in the read buffer
117 static NTSTATUS send_read_request_continue(struct dcerpc_pipe *p, DATA_BLOB *blob)
119 struct smb_private *smb = p->transport.private;
121 struct smb_read_state *state;
122 struct smbcli_request *req;
124 state = talloc_p(smb, struct smb_read_state);
126 return NT_STATUS_NO_MEMORY;
132 state->data = data_blob_talloc(state, NULL, 0x2000);
134 uint32_t frag_length = blob->length>=16?
135 dcerpc_get_frag_length(blob):0x2000;
136 state->received = blob->length;
137 state->data = data_blob_talloc(state, NULL, frag_length);
138 if (!state->data.data) {
140 return NT_STATUS_NO_MEMORY;
142 memcpy(state->data.data, blob->data, blob->length);
145 state->io = talloc_p(state, union smb_read);
148 io->generic.level = RAW_READ_READX;
149 io->readx.in.fnum = smb->fnum;
150 io->readx.in.mincnt = state->data.length - state->received;
151 io->readx.in.maxcnt = io->readx.in.mincnt;
152 io->readx.in.offset = 0;
153 io->readx.in.remaining = 0;
154 io->readx.out.data = state->data.data + state->received;
155 req = smb_raw_read_send(smb->tree, io);
157 return NT_STATUS_NO_MEMORY;
160 req->async.fn = smb_read_callback;
161 req->async.private = state;
170 trigger a read request from the server
172 static NTSTATUS send_read_request(struct dcerpc_pipe *p)
174 return send_read_request_continue(p, NULL);
178 this holds the state of an in-flight trans call
180 struct smb_trans_state {
181 struct dcerpc_pipe *p;
182 struct smbcli_request *req;
183 struct smb_trans2 *trans;
187 called when a trans request has completed
189 static void smb_trans_callback(struct smbcli_request *req)
191 struct smb_trans_state *state = req->async.private;
192 struct dcerpc_pipe *p = state->p;
195 status = smb_raw_trans_recv(req, state, state->trans);
197 if (NT_STATUS_IS_ERR(status)) {
198 pipe_dead(p, status);
202 if (!NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
203 p->transport.recv_data(p, &state->trans->out.data, NT_STATUS_OK);
208 /* there is more to receive - setup a readx */
209 send_read_request_continue(p, &state->trans->out.data);
214 send a SMBtrans style request
216 static NTSTATUS smb_send_trans_request(struct dcerpc_pipe *p, DATA_BLOB *blob)
218 struct smb_private *smb = p->transport.private;
219 struct smb_trans2 *trans;
221 struct smb_trans_state *state;
223 state = talloc_p(smb, struct smb_trans_state);
225 return NT_STATUS_NO_MEMORY;
229 state->trans = talloc_p(state, struct smb_trans2);
230 trans = state->trans;
232 trans->in.data = *blob;
233 trans->in.params = data_blob(NULL, 0);
235 setup[0] = TRANSACT_DCERPCCMD;
236 setup[1] = smb->fnum;
238 trans->in.max_param = 0;
239 trans->in.max_data = 0x8000;
240 trans->in.max_setup = 0;
241 trans->in.setup_count = 2;
243 trans->in.timeout = 0;
244 trans->in.setup = setup;
245 trans->in.trans_name = "\\PIPE\\";
247 state->req = smb_raw_trans_send(smb->tree, trans);
248 if (state->req == NULL) {
250 return NT_STATUS_NO_MEMORY;
253 state->req->async.fn = smb_trans_callback;
254 state->req->async.private = state;
260 called when a write request has completed
262 static void smb_write_callback(struct smbcli_request *req)
264 struct dcerpc_pipe *p = req->async.private;
266 if (!NT_STATUS_IS_OK(req->status)) {
267 DEBUG(0,("dcerpc_smb: write callback error\n"));
268 pipe_dead(p, req->status);
271 smbcli_request_destroy(req);
275 send a packet to the server
277 static NTSTATUS smb_send_request(struct dcerpc_pipe *p, DATA_BLOB *blob, BOOL trigger_read)
279 struct smb_private *smb = p->transport.private;
281 struct smbcli_request *req;
284 return smb_send_trans_request(p, blob);
287 io.generic.level = RAW_WRITE_WRITEX;
288 io.writex.in.fnum = smb->fnum;
289 io.writex.in.offset = 0;
290 io.writex.in.wmode = PIPE_START_MESSAGE;
291 io.writex.in.remaining = blob->length;
292 io.writex.in.count = blob->length;
293 io.writex.in.data = blob->data;
295 req = smb_raw_write_send(smb->tree, &io);
297 return NT_STATUS_NO_MEMORY;
300 req->async.fn = smb_write_callback;
301 req->async.private = p;
304 send_read_request(p);
311 return the event context for the pipe, so the caller can wait
312 for events asynchronously
314 static struct event_context *smb_event_context(struct dcerpc_pipe *p)
316 struct smb_private *smb = p->transport.private;
318 return smb->tree->session->transport->event.ctx;
323 shutdown SMB pipe connection
325 static NTSTATUS smb_shutdown_pipe(struct dcerpc_pipe *p)
327 struct smb_private *smb = p->transport.private;
330 /* maybe we're still starting up */
331 if (!smb) return NT_STATUS_OK;
333 c.close.level = RAW_CLOSE_CLOSE;
334 c.close.in.fnum = smb->fnum;
335 c.close.in.write_time = 0;
336 smb_raw_close(smb->tree, &c);
337 smbcli_tree_close(smb->tree);
343 return SMB server name
345 static const char *smb_peer_name(struct dcerpc_pipe *p)
347 struct smb_private *smb = p->transport.private;
348 return smb->tree->session->transport->called.name;
352 fetch the user session key
354 static NTSTATUS smb_session_key(struct dcerpc_pipe *p, DATA_BLOB *session_key)
356 struct smb_private *smb = p->transport.private;
358 if (smb->tree->session->user_session_key.data) {
359 *session_key = smb->tree->session->user_session_key;
362 return NT_STATUS_NO_USER_SESSION_KEY;
366 open a rpc connection to a named pipe
368 NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe **p,
369 struct smbcli_tree *tree,
370 const char *pipe_name)
372 struct smb_private *smb;
378 asprintf(&name, "\\%s", pipe_name);
380 return NT_STATUS_NO_MEMORY;
383 io.ntcreatex.level = RAW_OPEN_NTCREATEX;
384 io.ntcreatex.in.flags = 0;
385 io.ntcreatex.in.root_fid = 0;
386 io.ntcreatex.in.access_mask =
387 STD_RIGHT_READ_CONTROL_ACCESS |
388 SA_RIGHT_FILE_WRITE_ATTRIBUTES |
389 SA_RIGHT_FILE_WRITE_EA |
390 GENERIC_RIGHTS_FILE_READ |
391 GENERIC_RIGHTS_FILE_WRITE;
392 io.ntcreatex.in.file_attr = 0;
393 io.ntcreatex.in.alloc_size = 0;
394 io.ntcreatex.in.share_access =
395 NTCREATEX_SHARE_ACCESS_READ |
396 NTCREATEX_SHARE_ACCESS_WRITE;
397 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
398 io.ntcreatex.in.create_options = 0;
399 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
400 io.ntcreatex.in.security_flags = 0;
401 io.ntcreatex.in.fname = name;
403 mem_ctx = talloc_init("torture_rpc_connection");
406 return NT_STATUS_NO_MEMORY;
408 status = smb_raw_open(tree, mem_ctx, &io);
410 talloc_free(mem_ctx);
412 if (!NT_STATUS_IS_OK(status)) {
416 if (!(*p = dcerpc_pipe_init())) {
417 return NT_STATUS_NO_MEMORY;
421 fill in the transport methods
423 (*p)->transport.transport = NCACN_NP;
424 (*p)->transport.private = NULL;
425 (*p)->transport.shutdown_pipe = smb_shutdown_pipe;
426 (*p)->transport.peer_name = smb_peer_name;
428 (*p)->transport.send_request = smb_send_request;
429 (*p)->transport.send_read = send_read_request;
430 (*p)->transport.event_context = smb_event_context;
431 (*p)->transport.recv_data = NULL;
433 /* Over-ride the default session key with the SMB session key */
434 (*p)->security_state.session_key = smb_session_key;
436 smb = talloc((*p), sizeof(*smb));
438 dcerpc_pipe_close(*p);
439 return NT_STATUS_NO_MEMORY;
442 smb->fnum = io.ntcreatex.out.fnum;
445 (*p)->transport.private = smb;
446 tree->reference_count++;
452 return the SMB tree used for a dcerpc over SMB pipe
454 struct smbcli_tree *dcerpc_smb_tree(struct dcerpc_pipe *p)
456 struct smb_private *smb = p->transport.private;
458 if (p->transport.transport != NCACN_NP) {