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