1 /*
2    Unix SMB/CIFS implementation.
3    default IPC$ NTVFS backend
4 
5    Copyright (C) Andrew Tridgell 2003
6    Copyright (C) Stefan (metze) Metzmacher 2004-2005
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 /*
23   this implements the IPC$ backend, called by the NTVFS subsystem to
24   handle requests on IPC$ shares
25 */
26 
27 
28 #include "includes.h"
29 #include "lib/util/dlinklist.h"
30 #include "ntvfs/ntvfs.h"
31 #include "libcli/rap/rap.h"
32 #include "ntvfs/ipc/proto.h"
33 #include "rpc_server/dcerpc_server.h"
34 #include "libcli/raw/ioctl.h"
35 
36 /* this is the private structure used to keep the state of an open
37    ipc$ connection. It needs to keep information about all open
38    pipes */
39 struct ipc_private {
40 	struct ntvfs_module_context *ntvfs;
41 
42 	struct dcesrv_context *dcesrv;
43 
44 	/* a list of open pipes */
45 	struct pipe_state {
46 		struct pipe_state *next, *prev;
47 		struct ipc_private *private;
48 		const char *pipe_name;
49 		struct ntvfs_handle *handle;
50 		struct dcesrv_connection *dce_conn;
51 		uint16_t ipc_state;
52 	} *pipe_list;
53 };
54 
55 
56 /*
57   find a open pipe give a file handle
58 */
pipe_state_find(struct ipc_private * private,struct ntvfs_handle * handle)59 static struct pipe_state *pipe_state_find(struct ipc_private *private, struct ntvfs_handle *handle)
60 {
61 	struct pipe_state *s;
62 	void *p;
63 
64 	p = ntvfs_handle_get_backend_data(handle, private->ntvfs);
65 	if (!p) return NULL;
66 
67 	s = talloc_get_type(p, struct pipe_state);
68 	if (!s) return NULL;
69 
70 	return s;
71 }
72 
73 /*
74   find a open pipe give a wire fnum
75 */
pipe_state_find_key(struct ipc_private * private,struct ntvfs_request * req,const DATA_BLOB * key)76 static struct pipe_state *pipe_state_find_key(struct ipc_private *private, struct ntvfs_request *req, const DATA_BLOB *key)
77 {
78 	struct ntvfs_handle *h;
79 
80 	h = ntvfs_handle_search_by_wire_key(private->ntvfs, req, key);
81 	if (!h) return NULL;
82 
83 	return pipe_state_find(private, h);
84 }
85 
86 
87 /*
88   connect to a share - always works
89 */
ipc_connect(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,const char * sharename)90 static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
91 			    struct ntvfs_request *req, const char *sharename)
92 {
93 	NTSTATUS status;
94 	struct ipc_private *private;
95 
96 	ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "IPC");
97 	NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
98 
99 	ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "IPC");
100 	NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
101 
102 	/* prepare the private state for this connection */
103 	private = talloc(ntvfs, struct ipc_private);
104 	NT_STATUS_HAVE_NO_MEMORY(private);
105 
106 	ntvfs->private_data = private;
107 
108 	private->ntvfs = ntvfs;
109 	private->pipe_list = NULL;
110 
111 	/* setup the DCERPC server subsystem */
112 	status = dcesrv_init_ipc_context(private, &private->dcesrv);
113 	NT_STATUS_NOT_OK_RETURN(status);
114 
115 	return NT_STATUS_OK;
116 }
117 
118 /*
119   disconnect from a share
120 */
ipc_disconnect(struct ntvfs_module_context * ntvfs)121 static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
122 {
123 	return NT_STATUS_OK;
124 }
125 
126 /*
127   delete a file
128 */
ipc_unlink(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_unlink * unl)129 static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
130 			   struct ntvfs_request *req,
131 			   union smb_unlink *unl)
132 {
133 	return NT_STATUS_ACCESS_DENIED;
134 }
135 
136 /*
137   check if a directory exists
138 */
ipc_chkpath(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_chkpath * cp)139 static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
140 			    struct ntvfs_request *req,
141 			    union smb_chkpath *cp)
142 {
143 	return NT_STATUS_ACCESS_DENIED;
144 }
145 
146 /*
147   return info on a pathname
148 */
ipc_qpathinfo(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_fileinfo * info)149 static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
150 			      struct ntvfs_request *req, union smb_fileinfo *info)
151 {
152 	return NT_STATUS_ACCESS_DENIED;
153 }
154 
155 /*
156   set info on a pathname
157 */
ipc_setpathinfo(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_setfileinfo * st)158 static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
159 				struct ntvfs_request *req, union smb_setfileinfo *st)
160 {
161 	return NT_STATUS_ACCESS_DENIED;
162 }
163 
164 
165 /*
166   destroy a open pipe structure
167 */
ipc_fd_destructor(struct pipe_state * p)168 static int ipc_fd_destructor(struct pipe_state *p)
169 {
170 	DLIST_REMOVE(p->private->pipe_list, p);
171 	return 0;
172 }
173 
ipc_get_my_addr(struct dcesrv_connection * dce_conn,TALLOC_CTX * mem_ctx)174 static struct socket_address *ipc_get_my_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
175 {
176 	struct ipc_private *private = dce_conn->transport.private_data;
177 
178 	return ntvfs_get_my_addr(private->ntvfs, mem_ctx);
179 }
180 
ipc_get_peer_addr(struct dcesrv_connection * dce_conn,TALLOC_CTX * mem_ctx)181 static struct socket_address *ipc_get_peer_addr(struct dcesrv_connection *dce_conn, TALLOC_CTX *mem_ctx)
182 {
183 	struct ipc_private *private = dce_conn->transport.private_data;
184 
185 	return ntvfs_get_peer_addr(private->ntvfs, mem_ctx);
186 }
187 
188 /*
189   open a file backend - used for MSRPC pipes
190 */
ipc_open_generic(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,const char * fname,struct pipe_state ** ps)191 static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs,
192 				 struct ntvfs_request *req, const char *fname,
193 				 struct pipe_state **ps)
194 {
195 	struct pipe_state *p;
196 	NTSTATUS status;
197 	struct dcerpc_binding *ep_description;
198 	struct ipc_private *private = ntvfs->private_data;
199 	struct ntvfs_handle *h;
200 
201 	status = ntvfs_handle_new(ntvfs, req, &h);
202 	NT_STATUS_NOT_OK_RETURN(status);
203 
204 	p = talloc(h, struct pipe_state);
205 	NT_STATUS_HAVE_NO_MEMORY(p);
206 
207 	ep_description = talloc(req, struct dcerpc_binding);
208 	NT_STATUS_HAVE_NO_MEMORY(ep_description);
209 
210 	while (fname[0] == '\\') fname++;
211 
212 	p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
213 	NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
214 
215 	p->handle = h;
216 	p->ipc_state = 0x5ff;
217 
218 	/*
219 	  we're all set, now ask the dcerpc server subsystem to open the
220 	  endpoint. At this stage the pipe isn't bound, so we don't
221 	  know what interface the user actually wants, just that they want
222 	  one of the interfaces attached to this pipe endpoint.
223 	*/
224 	ep_description->transport = NCACN_NP;
225 	ep_description->endpoint = talloc_reference(ep_description, p->pipe_name);
226 
227 	/* The session info is refcount-increased in the
228 	 * dcesrv_endpoint_search_connect() function
229 	 */
230 	status = dcesrv_endpoint_search_connect(private->dcesrv,
231 						p,
232 						ep_description,
233 						h->session_info,
234 						ntvfs->ctx->event_ctx,
235 						ntvfs->ctx->msg_ctx,
236 						ntvfs->ctx->server_id,
237 						0,
238 						&p->dce_conn);
239 	NT_STATUS_NOT_OK_RETURN(status);
240 
241 	p->dce_conn->transport.private_data		= private;
242 	p->dce_conn->transport.report_output_data	= NULL;
243 	p->dce_conn->transport.get_my_addr		= ipc_get_my_addr;
244 	p->dce_conn->transport.get_peer_addr		= ipc_get_peer_addr;
245 
246 	DLIST_ADD(private->pipe_list, p);
247 
248 	p->private = private;
249 
250 	talloc_set_destructor(p, ipc_fd_destructor);
251 
252 	status = ntvfs_handle_set_backend_data(h, private->ntvfs, p);
253 	NT_STATUS_NOT_OK_RETURN(status);
254 
255 	*ps = p;
256 	return NT_STATUS_OK;
257 }
258 
259 /*
260   open a file with ntcreatex - used for MSRPC pipes
261 */
ipc_open_ntcreatex(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_open * oi)262 static NTSTATUS ipc_open_ntcreatex(struct ntvfs_module_context *ntvfs,
263 				   struct ntvfs_request *req, union smb_open *oi)
264 {
265 	struct pipe_state *p;
266 	NTSTATUS status;
267 
268 	status = ipc_open_generic(ntvfs, req, oi->ntcreatex.in.fname, &p);
269 	if (!NT_STATUS_IS_OK(status)) {
270 		return status;
271 	}
272 
273 	ZERO_STRUCT(oi->ntcreatex.out);
274 	oi->ntcreatex.out.file.ntvfs= p->handle;
275 	oi->ntcreatex.out.ipc_state = p->ipc_state;
276 	oi->ntcreatex.out.file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
277 
278 	return status;
279 }
280 
281 /*
282   open a file with openx - used for MSRPC pipes
283 */
ipc_open_openx(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_open * oi)284 static NTSTATUS ipc_open_openx(struct ntvfs_module_context *ntvfs,
285 			       struct ntvfs_request *req, union smb_open *oi)
286 {
287 	struct pipe_state *p;
288 	NTSTATUS status;
289 	const char *fname = oi->openx.in.fname;
290 
291 	status = ipc_open_generic(ntvfs, req, fname, &p);
292 	if (!NT_STATUS_IS_OK(status)) {
293 		return status;
294 	}
295 
296 	ZERO_STRUCT(oi->openx.out);
297 	oi->openx.out.file.ntvfs= p->handle;
298 	oi->openx.out.ftype	= 2;
299 	oi->openx.out.devstate	= p->ipc_state;
300 
301 	return status;
302 }
303 
304 /*
305   open a file with SMB2 Create - used for MSRPC pipes
306 */
ipc_open_smb2(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_open * oi)307 static NTSTATUS ipc_open_smb2(struct ntvfs_module_context *ntvfs,
308 			      struct ntvfs_request *req, union smb_open *oi)
309 {
310 	struct pipe_state *p;
311 	NTSTATUS status;
312 
313 	status = ipc_open_generic(ntvfs, req, oi->smb2.in.fname, &p);
314 	NT_STATUS_NOT_OK_RETURN(status);
315 
316 	oi->smb2.out.file.ntvfs		= p->handle;
317 	oi->smb2.out.oplock_flags	= oi->smb2.in.oplock_flags;
318 	oi->smb2.out.create_action	= NTCREATEX_ACTION_EXISTED;
319 	oi->smb2.out.create_time	= 0;
320 	oi->smb2.out.access_time	= 0;
321 	oi->smb2.out.write_time		= 0;
322 	oi->smb2.out.change_time	= 0;
323 	oi->smb2.out.alloc_size		= 4096;
324 	oi->smb2.out.size		= 0;
325 	oi->smb2.out.file_attr		= FILE_ATTRIBUTE_NORMAL;
326 	oi->smb2.out._pad		= 0;
327 	oi->smb2.out.blob		= data_blob(NULL, 0);
328 
329 	return status;
330 }
331 
332 /*
333   open a file - used for MSRPC pipes
334 */
ipc_open(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_open * oi)335 static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
336 				struct ntvfs_request *req, union smb_open *oi)
337 {
338 	NTSTATUS status;
339 
340 	switch (oi->generic.level) {
341 	case RAW_OPEN_NTCREATEX:
342 		status = ipc_open_ntcreatex(ntvfs, req, oi);
343 		break;
344 	case RAW_OPEN_OPENX:
345 		status = ipc_open_openx(ntvfs, req, oi);
346 		break;
347 	case RAW_OPEN_SMB2:
348 		status = ipc_open_smb2(ntvfs, req, oi);
349 		break;
350 	default:
351 		status = NT_STATUS_NOT_SUPPORTED;
352 		break;
353 	}
354 
355 	return status;
356 }
357 
358 /*
359   create a directory
360 */
ipc_mkdir(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_mkdir * md)361 static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
362 			  struct ntvfs_request *req, union smb_mkdir *md)
363 {
364 	return NT_STATUS_ACCESS_DENIED;
365 }
366 
367 /*
368   remove a directory
369 */
ipc_rmdir(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,struct smb_rmdir * rd)370 static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
371 			  struct ntvfs_request *req, struct smb_rmdir *rd)
372 {
373 	return NT_STATUS_ACCESS_DENIED;
374 }
375 
376 /*
377   rename a set of files
378 */
ipc_rename(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_rename * ren)379 static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
380 			   struct ntvfs_request *req, union smb_rename *ren)
381 {
382 	return NT_STATUS_ACCESS_DENIED;
383 }
384 
385 /*
386   copy a set of files
387 */
ipc_copy(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,struct smb_copy * cp)388 static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
389 			 struct ntvfs_request *req, struct smb_copy *cp)
390 {
391 	return NT_STATUS_ACCESS_DENIED;
392 }
393 
ipc_readx_dcesrv_output(void * private_data,DATA_BLOB * out,size_t * nwritten)394 static NTSTATUS ipc_readx_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
395 {
396 	DATA_BLOB *blob = private_data;
397 
398 	if (out->length < blob->length) {
399 		blob->length = out->length;
400 	}
401 	memcpy(blob->data, out->data, blob->length);
402 	*nwritten = blob->length;
403 	return NT_STATUS_OK;
404 }
405 
406 /*
407   read from a file
408 */
ipc_read(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_read * rd)409 static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
410 			 struct ntvfs_request *req, union smb_read *rd)
411 {
412 	struct ipc_private *private = ntvfs->private_data;
413 	DATA_BLOB data;
414 	struct pipe_state *p;
415 	NTSTATUS status = NT_STATUS_OK;
416 
417 	if (rd->generic.level != RAW_READ_GENERIC) {
418 		return ntvfs_map_read(ntvfs, req, rd);
419 	}
420 
421 	p = pipe_state_find(private, rd->readx.in.file.ntvfs);
422 	if (!p) {
423 		return NT_STATUS_INVALID_HANDLE;
424 	}
425 
426 	data.length = rd->readx.in.maxcnt;
427 	data.data = rd->readx.out.data;
428 	if (data.length > UINT16_MAX) {
429 		data.length = UINT16_MAX;
430 	}
431 
432 	if (data.length != 0) {
433 		status = dcesrv_output(p->dce_conn, &data, ipc_readx_dcesrv_output);
434 		if (NT_STATUS_IS_ERR(status)) {
435 			return status;
436 		}
437 	}
438 
439 	rd->readx.out.remaining = 0;
440 	rd->readx.out.compaction_mode = 0;
441 	rd->readx.out.nread = data.length;
442 
443 	return status;
444 }
445 
446 /*
447   write to a file
448 */
ipc_write(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_write * wr)449 static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
450 			  struct ntvfs_request *req, union smb_write *wr)
451 {
452 	struct ipc_private *private = ntvfs->private_data;
453 	DATA_BLOB data;
454 	struct pipe_state *p;
455 	NTSTATUS status;
456 
457 	if (wr->generic.level != RAW_WRITE_GENERIC) {
458 		return ntvfs_map_write(ntvfs, req, wr);
459 	}
460 
461 	data.data = discard_const_p(void, wr->writex.in.data);
462 	data.length = wr->writex.in.count;
463 
464 	p = pipe_state_find(private, wr->writex.in.file.ntvfs);
465 	if (!p) {
466 		return NT_STATUS_INVALID_HANDLE;
467 	}
468 
469 	status = dcesrv_input(p->dce_conn, &data);
470 	if (!NT_STATUS_IS_OK(status)) {
471 		return status;
472 	}
473 
474 	wr->writex.out.nwritten = data.length;
475 	wr->writex.out.remaining = 0;
476 
477 	return NT_STATUS_OK;
478 }
479 
480 /*
481   seek in a file
482 */
ipc_seek(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_seek * io)483 static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
484 			 struct ntvfs_request *req,
485 			 union smb_seek *io)
486 {
487 	return NT_STATUS_ACCESS_DENIED;
488 }
489 
490 /*
491   flush a file
492 */
ipc_flush(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_flush * io)493 static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
494 			  struct ntvfs_request *req,
495 			  union smb_flush *io)
496 {
497 	return NT_STATUS_ACCESS_DENIED;
498 }
499 
500 /*
501   close a file
502 */
ipc_close(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_close * io)503 static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
504 			  struct ntvfs_request *req, union smb_close *io)
505 {
506 	struct ipc_private *private = ntvfs->private_data;
507 	struct pipe_state *p;
508 
509 	if (io->generic.level != RAW_CLOSE_CLOSE) {
510 		return ntvfs_map_close(ntvfs, req, io);
511 	}
512 
513 	p = pipe_state_find(private, io->close.in.file.ntvfs);
514 	if (!p) {
515 		return NT_STATUS_INVALID_HANDLE;
516 	}
517 
518 	talloc_free(p);
519 
520 	return NT_STATUS_OK;
521 }
522 
523 /*
524   exit - closing files
525 */
ipc_exit(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req)526 static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
527 			 struct ntvfs_request *req)
528 {
529 	struct ipc_private *private = ntvfs->private_data;
530 	struct pipe_state *p, *next;
531 
532 	for (p=private->pipe_list; p; p=next) {
533 		next = p->next;
534 		if (p->handle->session_info == req->session_info &&
535 		    p->handle->smbpid == req->smbpid) {
536 			talloc_free(p);
537 		}
538 	}
539 
540 	return NT_STATUS_OK;
541 }
542 
543 /*
544   logoff - closing files open by the user
545 */
ipc_logoff(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req)546 static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
547 			   struct ntvfs_request *req)
548 {
549 	struct ipc_private *private = ntvfs->private_data;
550 	struct pipe_state *p, *next;
551 
552 	for (p=private->pipe_list; p; p=next) {
553 		next = p->next;
554 		if (p->handle->session_info == req->session_info) {
555 			talloc_free(p);
556 		}
557 	}
558 
559 	return NT_STATUS_OK;
560 }
561 
562 /*
563   setup for an async call
564 */
ipc_async_setup(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,void * private)565 static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
566 				struct ntvfs_request *req,
567 				void *private)
568 {
569 	return NT_STATUS_OK;
570 }
571 
572 /*
573   cancel an async call
574 */
ipc_cancel(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req)575 static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
576 			   struct ntvfs_request *req)
577 {
578 	return NT_STATUS_UNSUCCESSFUL;
579 }
580 
581 /*
582   lock a byte range
583 */
ipc_lock(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_lock * lck)584 static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
585 			 struct ntvfs_request *req, union smb_lock *lck)
586 {
587 	return NT_STATUS_ACCESS_DENIED;
588 }
589 
590 /*
591   set info on a open file
592 */
ipc_setfileinfo(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_setfileinfo * info)593 static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
594 				struct ntvfs_request *req, union smb_setfileinfo *info)
595 {
596 	return NT_STATUS_ACCESS_DENIED;
597 }
598 
599 /*
600   query info on a open file
601 */
ipc_qfileinfo(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_fileinfo * info)602 static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
603 			      struct ntvfs_request *req, union smb_fileinfo *info)
604 {
605 	return NT_STATUS_ACCESS_DENIED;
606 }
607 
608 
609 /*
610   return filesystem info
611 */
ipc_fsinfo(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_fsinfo * fs)612 static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
613 			   struct ntvfs_request *req, union smb_fsinfo *fs)
614 {
615 	return NT_STATUS_ACCESS_DENIED;
616 }
617 
618 /*
619   return print queue info
620 */
ipc_lpq(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_lpq * lpq)621 static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
622 			struct ntvfs_request *req, union smb_lpq *lpq)
623 {
624 	return NT_STATUS_ACCESS_DENIED;
625 }
626 
627 /*
628    list files in a directory matching a wildcard pattern
629 */
ipc_search_first(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_search_first * io,void * search_private,BOOL (* callback)(void *,union smb_search_data *))630 static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
631 			  struct ntvfs_request *req, union smb_search_first *io,
632 			  void *search_private,
633 			  BOOL (*callback)(void *, union smb_search_data *))
634 {
635 	return NT_STATUS_ACCESS_DENIED;
636 }
637 
638 /*
639    continue listing files in a directory
640 */
ipc_search_next(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_search_next * io,void * search_private,BOOL (* callback)(void *,union smb_search_data *))641 static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
642 			 struct ntvfs_request *req, union smb_search_next *io,
643 			 void *search_private,
644 			 BOOL (*callback)(void *, union smb_search_data *))
645 {
646 	return NT_STATUS_ACCESS_DENIED;
647 }
648 
649 /*
650    end listing files in a directory
651 */
ipc_search_close(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_search_close * io)652 static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
653 			  struct ntvfs_request *req, union smb_search_close *io)
654 {
655 	return NT_STATUS_ACCESS_DENIED;
656 }
657 
ipc_trans_dcesrv_output(void * private_data,DATA_BLOB * out,size_t * nwritten)658 static NTSTATUS ipc_trans_dcesrv_output(void *private_data, DATA_BLOB *out, size_t *nwritten)
659 {
660 	NTSTATUS status = NT_STATUS_OK;
661 	DATA_BLOB *blob = private_data;
662 
663 	if (out->length > blob->length) {
664 		status = STATUS_BUFFER_OVERFLOW;
665 	}
666 
667 	if (out->length < blob->length) {
668 		blob->length = out->length;
669 	}
670 	memcpy(blob->data, out->data, blob->length);
671 	*nwritten = blob->length;
672 	return status;
673 }
674 
675 /* SMBtrans - handle a DCERPC command */
ipc_dcerpc_cmd(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,struct smb_trans2 * trans)676 static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
677 			       struct ntvfs_request *req, struct smb_trans2 *trans)
678 {
679 	struct pipe_state *p;
680 	struct ipc_private *private = ntvfs->private_data;
681 	NTSTATUS status;
682 	DATA_BLOB fnum_key;
683 	uint16_t fnum;
684 
685 	/*
686 	 * the fnum is in setup[1], a 16 bit value
687 	 * the setup[*] values are already in host byteorder
688 	 * but ntvfs_handle_search_by_wire_key() expects
689 	 * network byteorder
690 	 */
691 	SSVAL(&fnum, 0, trans->in.setup[1]);
692 	fnum_key = data_blob_const(&fnum, 2);
693 
694 	p = pipe_state_find_key(private, req, &fnum_key);
695 	if (!p) {
696 		return NT_STATUS_INVALID_HANDLE;
697 	}
698 
699 	trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
700 	if (!trans->out.data.data) {
701 		return NT_STATUS_NO_MEMORY;
702 	}
703 
704 	/* pass the data to the dcerpc server. Note that we don't
705 	   expect this to fail, and things like NDR faults are not
706 	   reported at this stage. Those sorts of errors happen in the
707 	   dcesrv_output stage */
708 	status = dcesrv_input(p->dce_conn, &trans->in.data);
709 	if (!NT_STATUS_IS_OK(status)) {
710 		return status;
711 	}
712 
713 	/*
714 	  now ask the dcerpc system for some output. This doesn't yet handle
715 	  async calls. Again, we only expect NT_STATUS_OK. If the call fails then
716 	  the error is encoded at the dcerpc level
717 	*/
718 	status = dcesrv_output(p->dce_conn, &trans->out.data, ipc_trans_dcesrv_output);
719 	if (NT_STATUS_IS_ERR(status)) {
720 		return status;
721 	}
722 
723 	trans->out.setup_count = 0;
724 	trans->out.setup = NULL;
725 	trans->out.params = data_blob(NULL, 0);
726 
727 	return status;
728 }
729 
730 
731 /* SMBtrans - set named pipe state */
ipc_set_nm_pipe_state(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,struct smb_trans2 * trans)732 static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
733 				      struct ntvfs_request *req, struct smb_trans2 *trans)
734 {
735 	struct ipc_private *private = ntvfs->private_data;
736 	struct pipe_state *p;
737 	DATA_BLOB fnum_key;
738 
739 	/* the fnum is in setup[1] */
740 	fnum_key = data_blob_const(&trans->in.setup[1], sizeof(trans->in.setup[1]));
741 
742 	p = pipe_state_find_key(private, req, &fnum_key);
743 	if (!p) {
744 		return NT_STATUS_INVALID_HANDLE;
745 	}
746 
747 	if (trans->in.params.length != 2) {
748 		return NT_STATUS_INVALID_PARAMETER;
749 	}
750 	p->ipc_state = SVAL(trans->in.params.data, 0);
751 
752 	trans->out.setup_count = 0;
753 	trans->out.setup = NULL;
754 	trans->out.params = data_blob(NULL, 0);
755 	trans->out.data = data_blob(NULL, 0);
756 
757 	return NT_STATUS_OK;
758 }
759 
760 
761 /* SMBtrans - used to provide access to SMB pipes */
ipc_trans(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,struct smb_trans2 * trans)762 static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
763 				struct ntvfs_request *req, struct smb_trans2 *trans)
764 {
765 	NTSTATUS status;
766 
767 	if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
768 		return ipc_rap_call(req, trans);
769 
770        	if (trans->in.setup_count != 2) {
771 		return NT_STATUS_INVALID_PARAMETER;
772 	}
773 
774 	switch (trans->in.setup[0]) {
775 	case TRANSACT_SETNAMEDPIPEHANDLESTATE:
776 		status = ipc_set_nm_pipe_state(ntvfs, req, trans);
777 		break;
778 	case TRANSACT_DCERPCCMD:
779 		status = ipc_dcerpc_cmd(ntvfs, req, trans);
780 		break;
781 	default:
782 		status = NT_STATUS_INVALID_PARAMETER;
783 		break;
784 	}
785 
786 	return status;
787 }
788 
ipc_ioctl_smb2(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_ioctl * io)789 static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
790 			       struct ntvfs_request *req, union smb_ioctl *io)
791 {
792 	struct pipe_state *p;
793 	struct ipc_private *private = ntvfs->private_data;
794 	NTSTATUS status;
795 
796 	switch (io->smb2.in.function) {
797 	case FSCTL_NAMED_PIPE_READ_WRITE:
798 		break;
799 
800 	default:
801 		return NT_STATUS_FS_DRIVER_REQUIRED;
802 	}
803 
804 	p = pipe_state_find(private, io->smb2.in.file.ntvfs);
805 	if (!p) {
806 		return NT_STATUS_INVALID_HANDLE;
807 	}
808 
809 	io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_response_size);
810 	NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
811 
812 	/* pass the data to the dcerpc server. Note that we don't
813 	   expect this to fail, and things like NDR faults are not
814 	   reported at this stage. Those sorts of errors happen in the
815 	   dcesrv_output stage */
816 	status = dcesrv_input(p->dce_conn, &io->smb2.in.out);
817 	NT_STATUS_NOT_OK_RETURN(status);
818 
819 	/*
820 	  now ask the dcerpc system for some output. This doesn't yet handle
821 	  async calls. Again, we only expect NT_STATUS_OK. If the call fails then
822 	  the error is encoded at the dcerpc level
823 	*/
824 	status = dcesrv_output(p->dce_conn, &io->smb2.out.out, ipc_trans_dcesrv_output);
825 	NT_STATUS_IS_ERR_RETURN(status);
826 
827 	io->smb2.out._pad	= 0;
828 	io->smb2.out.function	= io->smb2.in.function;
829 	io->smb2.out.unknown2	= 0;
830 	io->smb2.out.unknown3	= 0;
831 	io->smb2.out.in		= io->smb2.in.out;
832 
833 	return status;
834 }
835 
836 /*
837   ioctl interface
838 */
ipc_ioctl(struct ntvfs_module_context * ntvfs,struct ntvfs_request * req,union smb_ioctl * io)839 static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
840 			  struct ntvfs_request *req, union smb_ioctl *io)
841 {
842 	switch (io->generic.level) {
843 	case RAW_IOCTL_SMB2:
844 		return ipc_ioctl_smb2(ntvfs, req, io);
845 
846 	case RAW_IOCTL_SMB2_NO_HANDLE:
847 		return NT_STATUS_FS_DRIVER_REQUIRED;
848 
849 	default:
850 		return NT_STATUS_ACCESS_DENIED;
851 	}
852 
853 	return NT_STATUS_ACCESS_DENIED;
854 }
855 
856 
857 /*
858   initialialise the IPC backend, registering ourselves with the ntvfs subsystem
859  */
ntvfs_ipc_init(void)860 NTSTATUS ntvfs_ipc_init(void)
861 {
862 	NTSTATUS ret;
863 	struct ntvfs_ops ops;
864 	NTVFS_CURRENT_CRITICAL_SIZES(vers);
865 
866 	ZERO_STRUCT(ops);
867 
868 	/* fill in the name and type */
869 	ops.name = "default";
870 	ops.type = NTVFS_IPC;
871 
872 	/* fill in all the operations */
873 	ops.connect = ipc_connect;
874 	ops.disconnect = ipc_disconnect;
875 	ops.unlink = ipc_unlink;
876 	ops.chkpath = ipc_chkpath;
877 	ops.qpathinfo = ipc_qpathinfo;
878 	ops.setpathinfo = ipc_setpathinfo;
879 	ops.open = ipc_open;
880 	ops.mkdir = ipc_mkdir;
881 	ops.rmdir = ipc_rmdir;
882 	ops.rename = ipc_rename;
883 	ops.copy = ipc_copy;
884 	ops.ioctl = ipc_ioctl;
885 	ops.read = ipc_read;
886 	ops.write = ipc_write;
887 	ops.seek = ipc_seek;
888 	ops.flush = ipc_flush;
889 	ops.close = ipc_close;
890 	ops.exit = ipc_exit;
891 	ops.lock = ipc_lock;
892 	ops.setfileinfo = ipc_setfileinfo;
893 	ops.qfileinfo = ipc_qfileinfo;
894 	ops.fsinfo = ipc_fsinfo;
895 	ops.lpq = ipc_lpq;
896 	ops.search_first = ipc_search_first;
897 	ops.search_next = ipc_search_next;
898 	ops.search_close = ipc_search_close;
899 	ops.trans = ipc_trans;
900 	ops.logoff = ipc_logoff;
901 	ops.async_setup = ipc_async_setup;
902 	ops.cancel = ipc_cancel;
903 
904 	/* register ourselves with the NTVFS subsystem. */
905 	ret = ntvfs_register(&ops, &vers);
906 
907 	if (!NT_STATUS_IS_OK(ret)) {
908 		DEBUG(0,("Failed to register IPC backend!\n"));
909 		return ret;
910 	}
911 
912 	return ret;
913 }
914