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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 
24 #include "includes.h"
25 #include "libcli/raw/libcliraw.h"
26 #include "libcli/composite/composite.h"
27 #include "librpc/rpc/dcerpc.h"
28 
29 /* transport private information used by SMB pipe transport */
30 struct smb_private {
31 	uint16_t fnum;
32 	struct smbcli_tree *tree;
33 	const char *server_name;
34 };
35 
36 
37 /*
38   tell the dcerpc layer that the transport is dead
39 */
pipe_dead(struct dcerpc_connection * c,NTSTATUS status)40 static void pipe_dead(struct dcerpc_connection *c, NTSTATUS status)
41 {
42 	DEBUG_FN_ENTER;
43 
44         c->transport.recv_data(c, NULL, status);
45         DEBUG_FN_EXIT;
46 
47 }
48 
49 
50 /*
51    this holds the state of an in-flight call
52 */
53 struct smb_read_state {
54 	struct dcerpc_connection *c;
55 	struct smbcli_request *req;
56 	size_t received;
57 	DATA_BLOB data;
58 	union smb_read *io;
59 };
60 
61 /*
62   called when a read request has completed
63 */
smb_read_callback(struct smbcli_request * req)64 static void smb_read_callback(struct smbcli_request *req)
65 {
66 	DEBUG_FN_ENTER;
67 
68         struct smb_private *smb;
69 	struct smb_read_state *state;
70 	union smb_read *io;
71 	uint16_t frag_length;
72 	NTSTATUS status;
73 
74 	state = talloc_get_type(req->async.private, struct smb_read_state);
75 	smb = talloc_get_type(state->c->transport.private, struct smb_private);
76 	io = state->io;
77 
78 	status = smb_raw_read_recv(state->req, io);
79 	if (NT_STATUS_IS_ERR(status)) {
80 		talloc_steal(NULL, state);
81 		pipe_dead(state->c, status);
82 		talloc_free(state);
83 		return;
84 	}
85 
86 	state->received += io->readx.out.nread;
87 
88 	if (state->received < 16) {
89 		DEBUG(0,("dcerpc_smb: short packet (length %d) in read callback!\n",
90 			 (int)state->received));
91 		talloc_steal(NULL, state);
92 		pipe_dead(state->c, NT_STATUS_INFO_LENGTH_MISMATCH);
93 		talloc_free(state);
94 		return;
95 	}
96 
97 	frag_length = dcerpc_get_frag_length(&state->data);
98 
99 	if (frag_length <= state->received) {
100 		DATA_BLOB data = state->data;
101 		struct dcerpc_connection *c = state->c;
102 		data.length = state->received;
103 		talloc_steal(state->c, data.data);
104 		talloc_free(state);
105 		c->transport.recv_data(c, &data, NT_STATUS_OK);
106 		return;
107 	}
108 
109 	/* initiate another read request, as we only got part of a fragment */
110 	state->data.data = talloc_realloc(state, state->data.data, uint8_t, frag_length);
111 
112 	io->readx.in.mincnt = MIN(state->c->srv_max_xmit_frag,
113 				  frag_length - state->received);
114 	io->readx.in.maxcnt = io->readx.in.mincnt;
115 	io->readx.out.data = state->data.data + state->received;
116 
117 	state->req = smb_raw_read_send(smb->tree, io);
118 	if (state->req == NULL) {
119 		talloc_steal(NULL, state);
120 		pipe_dead(state->c, NT_STATUS_NO_MEMORY);
121 		talloc_free(state);
122 		return;
123 	}
124 
125 	state->req->async.fn = smb_read_callback;
126 	state->req->async.private = state;
127         DEBUG_FN_EXIT;
128 
129 }
130 
131 /*
132   trigger a read request from the server, possibly with some initial
133   data in the read buffer
134 */
send_read_request_continue(struct dcerpc_connection * c,DATA_BLOB * blob)135 static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLOB *blob)
136 {
137 	DEBUG_FN_ENTER;
138 
139         struct smb_private *smb = c->transport.private;
140 	union smb_read *io;
141 	struct smb_read_state *state;
142 	struct smbcli_request *req;
143 
144 	state = talloc(smb, struct smb_read_state);
145 	if (state == NULL) {
146 		return NT_STATUS_NO_MEMORY;
147 	}
148 
149 	state->c = c;
150 	if (blob == NULL) {
151 		state->received = 0;
152 		state->data = data_blob_talloc(state, NULL, 0x2000);
153 	} else {
154 		uint32_t frag_length = blob->length>=16?
155 			dcerpc_get_frag_length(blob):0x2000;
156 		state->received = blob->length;
157 		state->data = data_blob_talloc(state, NULL, frag_length);
158 		if (!state->data.data) {
159 			talloc_free(state);
160 			return NT_STATUS_NO_MEMORY;
161 		}
162                 /* Added by cgibbons@zenoss on 03/10/2010 - prevent a buffer
163                    overrun. This may happen if the data blob has specified
164                    an invalid fragment size out. Safety first! */
165                 if (blob->length > talloc_get_size(state->data.data)) {
166                     talloc_free(state);
167                     return NT_STATUS_NO_MEMORY;
168                 }
169 		memcpy(state->data.data, blob->data, blob->length);
170 	}
171 
172 	state->io = talloc(state, union smb_read);
173 
174 	io = state->io;
175 	io->generic.level = RAW_READ_READX;
176 	io->readx.in.file.fnum = smb->fnum;
177 	io->readx.in.mincnt = state->data.length - state->received;
178 	io->readx.in.maxcnt = io->readx.in.mincnt;
179 	io->readx.in.offset = 0;
180 	io->readx.in.remaining = 0;
181 	io->readx.in.read_for_execute = False;
182 	io->readx.out.data = state->data.data + state->received;
183 	req = smb_raw_read_send(smb->tree, io);
184 	if (req == NULL) {
185 		return NT_STATUS_NO_MEMORY;
186 	}
187 
188 	req->async.fn = smb_read_callback;
189 	req->async.private = state;
190 
191 	state->req = req;
192 
193         DEBUG_FN_EXIT;
194 
195 	return NT_STATUS_OK;
196 }
197 
198 
199 /*
200   trigger a read request from the server
201 */
send_read_request(struct dcerpc_connection * c)202 static NTSTATUS send_read_request(struct dcerpc_connection *c)
203 {
204 	DEBUG_FN_ENTER;
205 
206         DEBUG_FN_EXIT;
207         return send_read_request_continue(c, NULL);
208 }
209 
210 /*
211    this holds the state of an in-flight trans call
212 */
213 struct smb_trans_state {
214 	struct dcerpc_connection *c;
215 	struct smbcli_request *req;
216 	struct smb_trans2 *trans;
217 };
218 
219 /*
220   called when a trans request has completed
221 */
smb_trans_callback(struct smbcli_request * req)222 static void smb_trans_callback(struct smbcli_request *req)
223 {
224 	DEBUG_FN_ENTER;
225 
226         struct smb_trans_state *state = req->async.private;
227 	struct dcerpc_connection *c = state->c;
228 	NTSTATUS status;
229 
230 	status = smb_raw_trans_recv(req, state, state->trans);
231 
232 	if (NT_STATUS_IS_ERR(status)) {
233 	        DEBUG_FN_FAIL("smb_raw_trans_recv return error NTSTATUS");
234 		pipe_dead(c, status);
235 		return;
236 	}
237 
238 	if (!NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
239 		DATA_BLOB data = state->trans->out.data;
240 		talloc_steal(c, data.data);
241 		talloc_free(state);
242 		c->transport.recv_data(c, &data, NT_STATUS_OK);
243 		DEBUG_FN_EXIT_MSG("BUFFER_OVERFLOW");
244 		return;
245 	}
246 
247 	/* there is more to receive - setup a readx */
248 	send_read_request_continue(c, &state->trans->out.data);
249 	talloc_free(state);
250         DEBUG_FN_EXIT;
251 
252 }
253 
254 /*
255   send a SMBtrans style request
256 */
smb_send_trans_request(struct dcerpc_connection * c,DATA_BLOB * blob)257 static NTSTATUS smb_send_trans_request(struct dcerpc_connection *c, DATA_BLOB *blob)
258 {
259         DEBUG_FN_ENTER;
260 
261         struct smb_private *smb = c->transport.private;
262         struct smb_trans2 *trans;
263         uint16_t setup[2];
264 	struct smb_trans_state *state;
265 
266 	state = talloc(smb, struct smb_trans_state);
267 	if (state == NULL) {
268 		return NT_STATUS_NO_MEMORY;
269 	}
270 
271 	state->c = c;
272 	state->trans = talloc(state, struct smb_trans2);
273 	trans = state->trans;
274 
275         trans->in.data = *blob;
276         trans->in.params = data_blob(NULL, 0);
277 
278         setup[0] = TRANSACT_DCERPCCMD;
279         setup[1] = smb->fnum;
280 
281         trans->in.max_param = 0;
282         trans->in.max_data = smb_raw_max_trans_data(smb->tree, 0);
283         trans->in.max_setup = 0;
284         trans->in.setup_count = 2;
285         trans->in.flags = 0;
286         trans->in.timeout = 0;
287         trans->in.setup = setup;
288         trans->in.trans_name = "\\PIPE\\";
289 
290         state->req = smb_raw_trans_send(smb->tree, trans);
291 	if (state->req == NULL) {
292 		talloc_free(state);
293 		return NT_STATUS_NO_MEMORY;
294 	}
295 
296 	state->req->async.fn = smb_trans_callback;
297 	state->req->async.private = state;
298 
299 	talloc_steal(state, state->req);
300 
301         DEBUG_FN_EXIT;
302 
303         return NT_STATUS_OK;
304 }
305 
306 /*
307   called when a write request has completed
308 */
smb_write_callback(struct smbcli_request * req)309 static void smb_write_callback(struct smbcli_request *req)
310 {
311 	DEBUG_FN_ENTER;
312 
313         struct dcerpc_connection *c = req->async.private;
314 
315 	if (!NT_STATUS_IS_OK(req->status)) {
316 		DEBUG(0,("dcerpc_smb: write callback error\n"));
317 		talloc_steal(NULL, req);
318 		pipe_dead(c, req->status);
319 	}
320 
321 	smbcli_request_destroy(req);
322         DEBUG_FN_EXIT;
323 
324 }
325 
326 /*
327    send a packet to the server
328 */
smb_send_request(struct dcerpc_connection * c,DATA_BLOB * blob,BOOL trigger_read)329 static NTSTATUS smb_send_request(struct dcerpc_connection *c, DATA_BLOB *blob, BOOL trigger_read)
330 {
331 	DEBUG_FN_ENTER;
332 
333         struct smb_private *smb = c->transport.private;
334 	union smb_write io;
335 	struct smbcli_request *req;
336 
337 	if (trigger_read) {
338 		return smb_send_trans_request(c, blob);
339 	}
340 
341 	io.generic.level = RAW_WRITE_WRITEX;
342 	io.writex.in.file.fnum = smb->fnum;
343 	io.writex.in.offset = 0;
344 	io.writex.in.wmode = PIPE_START_MESSAGE;
345 	io.writex.in.remaining = blob->length;
346 	io.writex.in.count = blob->length;
347 	io.writex.in.data = blob->data;
348 
349 	/* we must not timeout at the smb level for rpc requests, as otherwise
350 	   signing/sealing can be messed up */
351 	smb->tree->session->transport->options.request_timeout = 0;
352 
353 	req = smb_raw_write_send(smb->tree, &io);
354 	if (req == NULL) {
355 		return NT_STATUS_NO_MEMORY;
356 	}
357 
358 	req->async.fn = smb_write_callback;
359 	req->async.private = c;
360 
361 	if (trigger_read) {
362 		send_read_request(c);
363 	}
364 
365         DEBUG_FN_EXIT;
366 
367 	return NT_STATUS_OK;
368 }
369 
370 /*
371    shutdown SMB pipe connection
372 */
smb_shutdown_pipe(struct dcerpc_connection * c)373 static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c)
374 {
375 	DEBUG_FN_ENTER;
376 
377         struct smb_private *smb = c->transport.private;
378 	union smb_close io;
379 	struct smbcli_request *req;
380 
381 	/* maybe we're still starting up */
382 	if (!smb) return NT_STATUS_OK;
383 
384 	io.close.level = RAW_CLOSE_CLOSE;
385 	io.close.in.file.fnum = smb->fnum;
386 	io.close.in.write_time = 0;
387 	req = smb_raw_close_send(smb->tree, &io);
388 	if (req != NULL) {
389 		/* we don't care if this fails, so just free it if it succeeds */
390 		req->async.fn = (void (*)(struct smbcli_request *))talloc_free;
391 	}
392 
393 	talloc_free(smb);
394 
395         DEBUG_FN_EXIT;
396 
397 	return NT_STATUS_OK;
398 }
399 
400 /*
401   return SMB server name (called name)
402 */
smb_peer_name(struct dcerpc_connection * c)403 static const char *smb_peer_name(struct dcerpc_connection *c)
404 {
405 	struct smb_private *smb = c->transport.private;
406 	return smb->server_name;
407 }
408 
409 /*
410   return remote name we make the actual connection (good for kerberos)
411 */
smb_target_hostname(struct dcerpc_connection * c)412 static const char *smb_target_hostname(struct dcerpc_connection *c)
413 {
414 	struct smb_private *smb = talloc_get_type(c->transport.private, struct smb_private);
415 	return smb->tree->session->transport->socket->hostname;
416 }
417 
418 /*
419   fetch the user session key
420 */
smb_session_key(struct dcerpc_connection * c,DATA_BLOB * session_key)421 static NTSTATUS smb_session_key(struct dcerpc_connection *c, DATA_BLOB *session_key)
422 {
423 	struct smb_private *smb = c->transport.private;
424 
425 	if (smb->tree->session->user_session_key.data) {
426 		*session_key = smb->tree->session->user_session_key;
427 		return NT_STATUS_OK;
428 	}
429 	return NT_STATUS_NO_USER_SESSION_KEY;
430 }
431 
432 struct pipe_open_smb_state {
433 	union smb_open *open;
434 	struct dcerpc_connection *c;
435 	struct smbcli_tree *tree;
436 	struct composite_context *ctx;
437 };
438 
439 static void pipe_open_recv(struct smbcli_request *req);
440 
dcerpc_pipe_open_smb_send(struct dcerpc_connection * c,struct smbcli_tree * tree,const char * pipe_name)441 struct composite_context *dcerpc_pipe_open_smb_send(struct dcerpc_connection *c,
442 						    struct smbcli_tree *tree,
443 						    const char *pipe_name)
444 {
445 	DEBUG_FN_ENTER;
446 
447         struct composite_context *ctx;
448 	struct pipe_open_smb_state *state;
449 	struct smbcli_request *req;
450 
451 	ctx = composite_create(c, c->event_ctx);
452 	if (ctx == NULL) return NULL;
453 
454 	state = talloc(ctx, struct pipe_open_smb_state);
455 	if (composite_nomem(state, ctx)) return ctx;
456 	ctx->private_data = state;
457 
458 	state->c = c;
459 	state->tree = tree;
460 	state->ctx = ctx;
461 
462 	state->open = talloc(state, union smb_open);
463 	if (composite_nomem(state->open, ctx)) return ctx;
464 
465 	state->open->ntcreatex.level = RAW_OPEN_NTCREATEX;
466 	state->open->ntcreatex.in.flags = 0;
467 	state->open->ntcreatex.in.root_fid = 0;
468 	state->open->ntcreatex.in.access_mask =
469 		SEC_STD_READ_CONTROL |
470 		SEC_FILE_WRITE_ATTRIBUTE |
471 		SEC_FILE_WRITE_EA |
472 		SEC_FILE_READ_DATA |
473 		SEC_FILE_WRITE_DATA;
474 	state->open->ntcreatex.in.file_attr = 0;
475 	state->open->ntcreatex.in.alloc_size = 0;
476 	state->open->ntcreatex.in.share_access =
477 		NTCREATEX_SHARE_ACCESS_READ |
478 		NTCREATEX_SHARE_ACCESS_WRITE;
479 	state->open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
480 	state->open->ntcreatex.in.create_options = 0;
481 	state->open->ntcreatex.in.impersonation =
482 		NTCREATEX_IMPERSONATION_IMPERSONATION;
483 	state->open->ntcreatex.in.security_flags = 0;
484 
485 	if ((strncasecmp(pipe_name, "/pipe/", 6) == 0) ||
486 	    (strncasecmp(pipe_name, "\\pipe\\", 6) == 0)) {
487 		pipe_name += 6;
488 	}
489 	state->open->ntcreatex.in.fname =
490 		(pipe_name[0] == '\\') ?
491 		talloc_strdup(state->open, pipe_name) :
492 		talloc_asprintf(state->open, "\\%s", pipe_name);
493 	if (composite_nomem(state->open->ntcreatex.in.fname, ctx)) return ctx;
494 
495 	req = smb_raw_open_send(tree, state->open);
496 	composite_continue_smb(ctx, req, pipe_open_recv, state);
497 
498         DEBUG_FN_EXIT;
499 	return ctx;
500 }
501 
pipe_open_recv(struct smbcli_request * req)502 static void pipe_open_recv(struct smbcli_request *req)
503 {
504 	DEBUG_FN_ENTER;
505 
506         struct pipe_open_smb_state *state = talloc_get_type(req->async.private,
507 					    struct pipe_open_smb_state);
508 	struct composite_context *ctx = state->ctx;
509 	struct dcerpc_connection *c = state->c;
510 	struct smb_private *smb;
511 
512 	ctx->status = smb_raw_open_recv(req, state, state->open);
513 	if (!composite_is_ok(ctx)) return;
514 
515 	/*
516 	  fill in the transport methods
517 	*/
518 	c->transport.transport       = NCACN_NP;
519 	c->transport.private         = NULL;
520 	c->transport.shutdown_pipe   = smb_shutdown_pipe;
521 	c->transport.peer_name       = smb_peer_name;
522 	c->transport.target_hostname = smb_target_hostname;
523 
524 	c->transport.send_request    = smb_send_request;
525 	c->transport.send_read       = send_read_request;
526 	c->transport.recv_data       = NULL;
527 
528 	/* Over-ride the default session key with the SMB session key */
529 	c->security_state.session_key = smb_session_key;
530 
531 	smb = talloc(c, struct smb_private);
532 	if (composite_nomem(smb, ctx)) return;
533 
534 	smb->fnum	= state->open->ntcreatex.out.file.fnum;
535 	smb->tree	= talloc_reference(smb, state->tree);
536 	smb->server_name= strupper_talloc(smb,
537 			  state->tree->session->transport->called.name);
538 	if (composite_nomem(smb->server_name, ctx)) return;
539 	c->transport.private = smb;
540 
541 	composite_done(ctx);
542 
543         DEBUG_FN_EXIT;
544 }
545 
dcerpc_pipe_open_smb_recv(struct composite_context * c)546 NTSTATUS dcerpc_pipe_open_smb_recv(struct composite_context *c)
547 {
548 	DEBUG_FN_ENTER;
549 
550         NTSTATUS status = composite_wait(c);
551 	talloc_free(c);
552 
553         DEBUG_FN_EXIT;
554 	return status;
555 }
556 
dcerpc_pipe_open_smb(struct dcerpc_connection * c,struct smbcli_tree * tree,const char * pipe_name)557 NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_connection *c,
558 			      struct smbcli_tree *tree,
559 			      const char *pipe_name)
560 {
561 	DEBUG_FN_ENTER;
562 
563         struct composite_context *ctx =	dcerpc_pipe_open_smb_send(c, tree,
564 								  pipe_name);
565 
566 	return dcerpc_pipe_open_smb_recv(ctx);
567 }
568 
569 /*
570   return the SMB tree used for a dcerpc over SMB pipe
571 */
dcerpc_smb_tree(struct dcerpc_connection * c)572 struct smbcli_tree *dcerpc_smb_tree(struct dcerpc_connection *c)
573 {
574 	struct smb_private *smb;
575 
576 	if (c->transport.transport != NCACN_NP) return NULL;
577 
578 	smb = talloc_get_type(c->transport.private, struct smb_private);
579 	if (!smb) return NULL;
580 
581 	return smb->tree;
582 }
583