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