Line data Source code
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 "../librpc/gen_ndr/rap.h"
31 : #include "ntvfs/ipc/proto.h"
32 : #include "../libcli/smb/smb_constants.h"
33 : #include "param/param.h"
34 : #include "../lib/tsocket/tsocket.h"
35 : #include "../libcli/named_pipe_auth/npa_tstream.h"
36 : #include "auth/auth.h"
37 : #include "auth/auth_sam_reply.h"
38 : #include "lib/socket/socket.h"
39 : #include "auth/credentials/credentials.h"
40 : #include "auth/credentials/credentials_krb5.h"
41 : #include "system/kerberos.h"
42 : #include "system/gssapi.h"
43 : #include "system/locale.h"
44 : #include "system/filesys.h"
45 :
46 : #undef strncasecmp
47 :
48 : /* this is the private structure used to keep the state of an open
49 : ipc$ connection. It needs to keep information about all open
50 : pipes */
51 : struct ipc_private {
52 : struct ntvfs_module_context *ntvfs;
53 :
54 : /* a list of open pipes */
55 : struct pipe_state {
56 : struct pipe_state *next, *prev;
57 : struct ipc_private *ipriv;
58 : const char *pipe_name;
59 : struct ntvfs_handle *handle;
60 : struct tstream_context *npipe;
61 : uint16_t file_type;
62 : uint16_t device_state;
63 : uint64_t allocation_size;
64 : struct tevent_queue *write_queue;
65 : struct tevent_queue *read_queue;
66 : } *pipe_list;
67 : };
68 :
69 :
70 : /*
71 : find a open pipe give a file handle
72 : */
73 51469 : static struct pipe_state *pipe_state_find(struct ipc_private *ipriv, struct ntvfs_handle *handle)
74 : {
75 0 : struct pipe_state *s;
76 0 : void *p;
77 :
78 51469 : p = ntvfs_handle_get_backend_data(handle, ipriv->ntvfs);
79 51469 : if (!p) return NULL;
80 :
81 51469 : s = talloc_get_type(p, struct pipe_state);
82 51469 : if (!s) return NULL;
83 :
84 51469 : return s;
85 : }
86 :
87 : /*
88 : find a open pipe give a wire fnum
89 : */
90 42 : static struct pipe_state *pipe_state_find_key(struct ipc_private *ipriv, struct ntvfs_request *req, const DATA_BLOB *key)
91 : {
92 0 : struct ntvfs_handle *h;
93 :
94 42 : h = ntvfs_handle_search_by_wire_key(ipriv->ntvfs, req, key);
95 42 : if (!h) return NULL;
96 :
97 33 : return pipe_state_find(ipriv, h);
98 : }
99 :
100 :
101 : /*
102 : connect to a share - always works
103 : */
104 1069 : static NTSTATUS ipc_connect(struct ntvfs_module_context *ntvfs,
105 : struct ntvfs_request *req,
106 : union smb_tcon* tcon)
107 : {
108 0 : struct ipc_private *ipriv;
109 0 : const char *sharename;
110 :
111 1069 : switch (tcon->generic.level) {
112 0 : case RAW_TCON_TCON:
113 0 : sharename = tcon->tcon.in.service;
114 0 : break;
115 35 : case RAW_TCON_TCONX:
116 35 : sharename = tcon->tconx.in.path;
117 35 : break;
118 1034 : case RAW_TCON_SMB2:
119 1034 : sharename = tcon->smb2.in.path;
120 1034 : break;
121 0 : default:
122 0 : return NT_STATUS_INVALID_LEVEL;
123 : }
124 :
125 1069 : if (strncmp(sharename, "\\\\", 2) == 0) {
126 1063 : char *p = strchr(sharename+2, '\\');
127 1063 : if (p) {
128 1063 : sharename = p + 1;
129 : }
130 : }
131 :
132 1069 : ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "IPC");
133 1069 : NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
134 :
135 1069 : ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "IPC");
136 1069 : NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
137 :
138 1069 : if (tcon->generic.level == RAW_TCON_TCONX) {
139 35 : tcon->tconx.out.fs_type = ntvfs->ctx->fs_type;
140 35 : tcon->tconx.out.dev_type = ntvfs->ctx->dev_type;
141 : }
142 :
143 : /* prepare the private state for this connection */
144 1069 : ipriv = talloc(ntvfs, struct ipc_private);
145 1069 : NT_STATUS_HAVE_NO_MEMORY(ipriv);
146 :
147 1069 : ntvfs->private_data = ipriv;
148 :
149 1069 : ipriv->ntvfs = ntvfs;
150 1069 : ipriv->pipe_list = NULL;
151 :
152 1069 : return NT_STATUS_OK;
153 : }
154 :
155 : /*
156 : disconnect from a share
157 : */
158 1069 : static NTSTATUS ipc_disconnect(struct ntvfs_module_context *ntvfs)
159 : {
160 1069 : return NT_STATUS_OK;
161 : }
162 :
163 : /*
164 : delete a file
165 : */
166 0 : static NTSTATUS ipc_unlink(struct ntvfs_module_context *ntvfs,
167 : struct ntvfs_request *req,
168 : union smb_unlink *unl)
169 : {
170 0 : return NT_STATUS_ACCESS_DENIED;
171 : }
172 :
173 : /*
174 : check if a directory exists
175 : */
176 0 : static NTSTATUS ipc_chkpath(struct ntvfs_module_context *ntvfs,
177 : struct ntvfs_request *req,
178 : union smb_chkpath *cp)
179 : {
180 0 : return NT_STATUS_ACCESS_DENIED;
181 : }
182 :
183 : /*
184 : return info on a pathname
185 : */
186 59 : static NTSTATUS ipc_qpathinfo(struct ntvfs_module_context *ntvfs,
187 : struct ntvfs_request *req, union smb_fileinfo *info)
188 : {
189 59 : switch (info->generic.level) {
190 29 : case RAW_FILEINFO_GENERIC:
191 29 : return NT_STATUS_INVALID_DEVICE_REQUEST;
192 1 : case RAW_FILEINFO_GETATTR:
193 1 : return NT_STATUS_ACCESS_DENIED;
194 29 : default:
195 29 : return ntvfs_map_qpathinfo(ntvfs, req, info);
196 : }
197 : }
198 :
199 : /*
200 : set info on a pathname
201 : */
202 0 : static NTSTATUS ipc_setpathinfo(struct ntvfs_module_context *ntvfs,
203 : struct ntvfs_request *req, union smb_setfileinfo *st)
204 : {
205 0 : return NT_STATUS_ACCESS_DENIED;
206 : }
207 :
208 :
209 : /*
210 : destroy a open pipe structure
211 : */
212 1246 : static int ipc_fd_destructor(struct pipe_state *p)
213 : {
214 1246 : DLIST_REMOVE(p->ipriv->pipe_list, p);
215 1246 : ntvfs_handle_remove_backend_data(p->handle, p->ipriv->ntvfs);
216 1246 : return 0;
217 : }
218 :
219 : struct ipc_open_state {
220 : struct ipc_private *ipriv;
221 : struct pipe_state *p;
222 : struct ntvfs_request *req;
223 : union smb_open *oi;
224 : struct auth_session_info_transport *session_info_transport;
225 : };
226 :
227 : static void ipc_open_done(struct tevent_req *subreq);
228 :
229 : /*
230 : check the pipename is valid
231 : */
232 1330 : static NTSTATUS validate_pipename(const char *name)
233 : {
234 9205 : while (*name) {
235 7875 : if (!isalnum(*name) && *name != '_') {
236 0 : return NT_STATUS_INVALID_PARAMETER;
237 : }
238 7875 : name++;
239 : }
240 1330 : return NT_STATUS_OK;
241 : }
242 :
243 : /*
244 : open a file - used for MSRPC pipes
245 : */
246 1330 : static NTSTATUS ipc_open(struct ntvfs_module_context *ntvfs,
247 : struct ntvfs_request *req, union smb_open *oi)
248 : {
249 0 : NTSTATUS status;
250 0 : struct pipe_state *p;
251 1330 : struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
252 : struct ipc_private);
253 0 : struct ntvfs_handle *h;
254 0 : struct ipc_open_state *state;
255 0 : struct tevent_req *subreq;
256 0 : const char *fname;
257 0 : const char *directory;
258 0 : const struct tsocket_address *remote_client_addr;
259 0 : const struct tsocket_address *local_server_addr;
260 :
261 1330 : switch (oi->generic.level) {
262 13 : case RAW_OPEN_NTCREATEX:
263 : case RAW_OPEN_NTTRANS_CREATE:
264 13 : fname = oi->ntcreatex.in.fname;
265 26 : while (fname[0] == '\\') fname++;
266 13 : break;
267 0 : case RAW_OPEN_OPENX:
268 0 : fname = oi->openx.in.fname;
269 0 : while (fname[0] == '\\') fname++;
270 0 : if (strncasecmp(fname, "PIPE\\", 5) != 0) {
271 0 : return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
272 : }
273 0 : while (fname[0] == '\\') fname++;
274 0 : break;
275 1317 : case RAW_OPEN_SMB2:
276 1317 : fname = oi->smb2.in.fname;
277 1317 : break;
278 0 : default:
279 0 : return NT_STATUS_NOT_SUPPORTED;
280 : }
281 :
282 1330 : directory = talloc_asprintf(req, "%s/np",
283 1330 : lpcfg_ncalrpc_dir(ipriv->ntvfs->ctx->lp_ctx));
284 1330 : NT_STATUS_HAVE_NO_MEMORY(directory);
285 :
286 1330 : state = talloc(req, struct ipc_open_state);
287 1330 : NT_STATUS_HAVE_NO_MEMORY(state);
288 :
289 1330 : status = ntvfs_handle_new(ntvfs, req, &h);
290 1330 : NT_STATUS_NOT_OK_RETURN(status);
291 :
292 1330 : p = talloc(h, struct pipe_state);
293 1330 : NT_STATUS_HAVE_NO_MEMORY(p);
294 :
295 : /* check for valid characters in name */
296 1330 : fname = strlower_talloc(p, fname);
297 :
298 1330 : status = validate_pipename(fname);
299 1330 : NT_STATUS_NOT_OK_RETURN(status);
300 :
301 1330 : p->pipe_name = talloc_asprintf(p, "\\pipe\\%s", fname);
302 1330 : NT_STATUS_HAVE_NO_MEMORY(p->pipe_name);
303 :
304 1330 : p->handle = h;
305 1330 : p->ipriv = ipriv;
306 :
307 1330 : p->write_queue = tevent_queue_create(p, "ipc_write_queue");
308 1330 : NT_STATUS_HAVE_NO_MEMORY(p->write_queue);
309 :
310 1330 : p->read_queue = tevent_queue_create(p, "ipc_read_queue");
311 1330 : NT_STATUS_HAVE_NO_MEMORY(p->read_queue);
312 :
313 1330 : state->ipriv = ipriv;
314 1330 : state->p = p;
315 1330 : state->req = req;
316 1330 : state->oi = oi;
317 :
318 1330 : status = auth_session_info_transport_from_session(state,
319 : req->session_info,
320 1330 : ipriv->ntvfs->ctx->event_ctx,
321 1330 : ipriv->ntvfs->ctx->lp_ctx,
322 : &state->session_info_transport);
323 :
324 1330 : NT_STATUS_NOT_OK_RETURN(status);
325 :
326 1330 : local_server_addr = ntvfs_get_local_address(ipriv->ntvfs);
327 1330 : remote_client_addr = ntvfs_get_remote_address(ipriv->ntvfs);
328 :
329 1330 : subreq = tstream_npa_connect_send(p,
330 1330 : ipriv->ntvfs->ctx->event_ctx,
331 : directory,
332 : fname,
333 : NCACN_NP,
334 : remote_client_addr,
335 : NULL,
336 : local_server_addr,
337 : NULL,
338 1330 : state->session_info_transport);
339 1330 : NT_STATUS_HAVE_NO_MEMORY(subreq);
340 1330 : tevent_req_set_callback(subreq, ipc_open_done, state);
341 :
342 1330 : req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
343 1330 : return NT_STATUS_OK;
344 : }
345 :
346 1330 : static void ipc_open_done(struct tevent_req *subreq)
347 : {
348 1330 : struct ipc_open_state *state = tevent_req_callback_data(subreq,
349 : struct ipc_open_state);
350 1330 : struct ipc_private *ipriv = state->ipriv;
351 1330 : struct pipe_state *p = state->p;
352 1330 : struct ntvfs_request *req = state->req;
353 1330 : union smb_open *oi = state->oi;
354 0 : int ret;
355 0 : int sys_errno;
356 0 : NTSTATUS status;
357 :
358 1330 : ret = tstream_npa_connect_recv(subreq, &sys_errno,
359 : p, &p->npipe,
360 : &p->file_type,
361 : &p->device_state,
362 : &p->allocation_size);
363 1330 : TALLOC_FREE(subreq);
364 1330 : if (ret == -1) {
365 84 : status = map_nt_error_from_unix_common(sys_errno);
366 84 : goto reply;
367 : }
368 :
369 1246 : DLIST_ADD(ipriv->pipe_list, p);
370 1246 : talloc_set_destructor(p, ipc_fd_destructor);
371 :
372 1246 : status = ntvfs_handle_set_backend_data(p->handle, ipriv->ntvfs, p);
373 1246 : if (!NT_STATUS_IS_OK(status)) {
374 0 : goto reply;
375 : }
376 :
377 1246 : switch (oi->generic.level) {
378 13 : case RAW_OPEN_NTCREATEX:
379 13 : ZERO_STRUCT(oi->ntcreatex.out);
380 13 : oi->ntcreatex.out.file.ntvfs = p->handle;
381 13 : oi->ntcreatex.out.oplock_level = 0;
382 13 : oi->ntcreatex.out.create_action = NTCREATEX_ACTION_EXISTED;
383 13 : oi->ntcreatex.out.create_time = 0;
384 13 : oi->ntcreatex.out.access_time = 0;
385 13 : oi->ntcreatex.out.write_time = 0;
386 13 : oi->ntcreatex.out.change_time = 0;
387 13 : oi->ntcreatex.out.attrib = FILE_ATTRIBUTE_NORMAL;
388 13 : oi->ntcreatex.out.alloc_size = p->allocation_size;
389 13 : oi->ntcreatex.out.size = 0;
390 13 : oi->ntcreatex.out.file_type = p->file_type;
391 13 : oi->ntcreatex.out.ipc_state = p->device_state;
392 13 : oi->ntcreatex.out.is_directory = 0;
393 13 : break;
394 0 : case RAW_OPEN_OPENX:
395 0 : ZERO_STRUCT(oi->openx.out);
396 0 : oi->openx.out.file.ntvfs = p->handle;
397 0 : oi->openx.out.attrib = FILE_ATTRIBUTE_NORMAL;
398 0 : oi->openx.out.write_time = 0;
399 0 : oi->openx.out.size = 0;
400 0 : oi->openx.out.access = 0;
401 0 : oi->openx.out.ftype = p->file_type;
402 0 : oi->openx.out.devstate = p->device_state;
403 0 : oi->openx.out.action = 0;
404 0 : oi->openx.out.unique_fid = 0;
405 0 : oi->openx.out.access_mask = 0;
406 0 : oi->openx.out.unknown = 0;
407 0 : break;
408 1233 : case RAW_OPEN_SMB2:
409 1233 : ZERO_STRUCT(oi->smb2.out);
410 1233 : oi->smb2.out.file.ntvfs = p->handle;
411 1233 : oi->smb2.out.oplock_level = oi->smb2.in.oplock_level;
412 1233 : oi->smb2.out.create_action = NTCREATEX_ACTION_EXISTED;
413 1233 : oi->smb2.out.create_time = 0;
414 1233 : oi->smb2.out.access_time = 0;
415 1233 : oi->smb2.out.write_time = 0;
416 1233 : oi->smb2.out.change_time = 0;
417 1233 : oi->smb2.out.alloc_size = p->allocation_size;
418 1233 : oi->smb2.out.size = 0;
419 1233 : oi->smb2.out.file_attr = FILE_ATTRIBUTE_NORMAL;
420 1233 : oi->smb2.out.reserved2 = 0;
421 1233 : break;
422 0 : default:
423 0 : break;
424 : }
425 :
426 1330 : reply:
427 1330 : req->async_states->status = status;
428 1330 : req->async_states->send_fn(req);
429 1330 : }
430 :
431 : /*
432 : create a directory
433 : */
434 0 : static NTSTATUS ipc_mkdir(struct ntvfs_module_context *ntvfs,
435 : struct ntvfs_request *req, union smb_mkdir *md)
436 : {
437 0 : return NT_STATUS_ACCESS_DENIED;
438 : }
439 :
440 : /*
441 : remove a directory
442 : */
443 0 : static NTSTATUS ipc_rmdir(struct ntvfs_module_context *ntvfs,
444 : struct ntvfs_request *req, struct smb_rmdir *rd)
445 : {
446 0 : return NT_STATUS_ACCESS_DENIED;
447 : }
448 :
449 : /*
450 : rename a set of files
451 : */
452 0 : static NTSTATUS ipc_rename(struct ntvfs_module_context *ntvfs,
453 : struct ntvfs_request *req, union smb_rename *ren)
454 : {
455 0 : return NT_STATUS_ACCESS_DENIED;
456 : }
457 :
458 : /*
459 : copy a set of files
460 : */
461 0 : static NTSTATUS ipc_copy(struct ntvfs_module_context *ntvfs,
462 : struct ntvfs_request *req, struct smb_copy *cp)
463 : {
464 0 : return NT_STATUS_ACCESS_DENIED;
465 : }
466 :
467 : struct ipc_readv_next_vector_state {
468 : uint8_t *buf;
469 : size_t len;
470 : off_t ofs;
471 : size_t remaining;
472 : };
473 :
474 48834 : static void ipc_readv_next_vector_init(struct ipc_readv_next_vector_state *s,
475 : uint8_t *buf, size_t len)
476 : {
477 48834 : ZERO_STRUCTP(s);
478 :
479 48834 : s->buf = buf;
480 48834 : s->len = MIN(len, UINT16_MAX);
481 48834 : }
482 :
483 146502 : static int ipc_readv_next_vector(struct tstream_context *stream,
484 : void *private_data,
485 : TALLOC_CTX *mem_ctx,
486 : struct iovec **_vector,
487 : size_t *count)
488 : {
489 146502 : struct ipc_readv_next_vector_state *state =
490 : (struct ipc_readv_next_vector_state *)private_data;
491 0 : struct iovec *vector;
492 0 : ssize_t pending;
493 0 : size_t wanted;
494 :
495 146502 : if (state->ofs == state->len) {
496 807 : *_vector = NULL;
497 807 : *count = 0;
498 807 : return 0;
499 : }
500 :
501 145695 : pending = tstream_pending_bytes(stream);
502 145695 : if (pending == -1) {
503 0 : return -1;
504 : }
505 :
506 145695 : if (pending == 0 && state->ofs != 0) {
507 : /* return a short read */
508 48027 : *_vector = NULL;
509 48027 : *count = 0;
510 48027 : return 0;
511 : }
512 :
513 97668 : if (pending == 0) {
514 : /* we want at least one byte and recheck again */
515 48834 : wanted = 1;
516 : } else {
517 48834 : size_t missing = state->len - state->ofs;
518 48834 : if (pending > missing) {
519 : /* there's more available */
520 0 : state->remaining = pending - missing;
521 0 : wanted = missing;
522 : } else {
523 : /* read what we can get and recheck in the next cycle */
524 48834 : wanted = pending;
525 : }
526 : }
527 :
528 97668 : vector = talloc_array(mem_ctx, struct iovec, 1);
529 97668 : if (!vector) {
530 0 : return -1;
531 : }
532 :
533 97668 : vector[0].iov_base = (char *) (state->buf + state->ofs);
534 97668 : vector[0].iov_len = wanted;
535 :
536 97668 : state->ofs += wanted;
537 :
538 97668 : *_vector = vector;
539 97668 : *count = 1;
540 97668 : return 0;
541 : }
542 :
543 : struct ipc_read_state {
544 : struct ipc_private *ipriv;
545 : struct pipe_state *p;
546 : struct ntvfs_request *req;
547 : union smb_read *rd;
548 : struct ipc_readv_next_vector_state next_vector;
549 : };
550 :
551 : static void ipc_read_done(struct tevent_req *subreq);
552 :
553 : /*
554 : read from a file
555 : */
556 2626 : static NTSTATUS ipc_read(struct ntvfs_module_context *ntvfs,
557 : struct ntvfs_request *req, union smb_read *rd)
558 : {
559 2626 : struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
560 : struct ipc_private);
561 0 : struct pipe_state *p;
562 0 : struct ipc_read_state *state;
563 0 : struct tevent_req *subreq;
564 :
565 2626 : if (rd->generic.level != RAW_READ_GENERIC) {
566 1313 : return ntvfs_map_read(ntvfs, req, rd);
567 : }
568 :
569 1313 : p = pipe_state_find(ipriv, rd->readx.in.file.ntvfs);
570 1313 : if (!p) {
571 0 : return NT_STATUS_INVALID_HANDLE;
572 : }
573 :
574 1313 : state = talloc(req, struct ipc_read_state);
575 1313 : NT_STATUS_HAVE_NO_MEMORY(state);
576 :
577 1313 : state->ipriv = ipriv;
578 1313 : state->p = p;
579 1313 : state->req = req;
580 1313 : state->rd = rd;
581 :
582 : /* rd->readx.out.data is already allocated */
583 1313 : ipc_readv_next_vector_init(&state->next_vector,
584 : rd->readx.out.data,
585 1313 : rd->readx.in.maxcnt);
586 :
587 1313 : subreq = tstream_readv_pdu_queue_send(req,
588 1313 : ipriv->ntvfs->ctx->event_ctx,
589 : p->npipe,
590 : p->read_queue,
591 : ipc_readv_next_vector,
592 1313 : &state->next_vector);
593 1313 : NT_STATUS_HAVE_NO_MEMORY(subreq);
594 1313 : tevent_req_set_callback(subreq, ipc_read_done, state);
595 :
596 1313 : req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
597 1313 : return NT_STATUS_OK;
598 : }
599 :
600 1313 : static void ipc_read_done(struct tevent_req *subreq)
601 : {
602 0 : struct ipc_read_state *state =
603 1313 : tevent_req_callback_data(subreq,
604 : struct ipc_read_state);
605 1313 : struct ntvfs_request *req = state->req;
606 1313 : union smb_read *rd = state->rd;
607 0 : int ret;
608 0 : int sys_errno;
609 0 : NTSTATUS status;
610 :
611 1313 : ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
612 1313 : TALLOC_FREE(subreq);
613 1313 : if (ret == -1) {
614 0 : status = map_nt_error_from_unix_common(sys_errno);
615 0 : goto reply;
616 : }
617 :
618 1313 : status = NT_STATUS_OK;
619 1313 : if (state->next_vector.remaining > 0) {
620 0 : status = STATUS_BUFFER_OVERFLOW;
621 : }
622 :
623 1313 : rd->readx.out.remaining = state->next_vector.remaining;
624 1313 : rd->readx.out.compaction_mode = 0;
625 1313 : rd->readx.out.nread = ret;
626 :
627 1313 : reply:
628 1313 : req->async_states->status = status;
629 1313 : req->async_states->send_fn(req);
630 1313 : }
631 :
632 : struct ipc_write_state {
633 : struct ipc_private *ipriv;
634 : struct pipe_state *p;
635 : struct ntvfs_request *req;
636 : union smb_write *wr;
637 : struct iovec iov;
638 : };
639 :
640 : static void ipc_write_done(struct tevent_req *subreq);
641 :
642 : /*
643 : write to a file
644 : */
645 2798 : static NTSTATUS ipc_write(struct ntvfs_module_context *ntvfs,
646 : struct ntvfs_request *req, union smb_write *wr)
647 : {
648 2798 : struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
649 : struct ipc_private);
650 0 : struct pipe_state *p;
651 0 : struct tevent_req *subreq;
652 0 : struct ipc_write_state *state;
653 :
654 2798 : if (wr->generic.level != RAW_WRITE_GENERIC) {
655 1399 : return ntvfs_map_write(ntvfs, req, wr);
656 : }
657 :
658 1399 : p = pipe_state_find(ipriv, wr->writex.in.file.ntvfs);
659 1399 : if (!p) {
660 0 : return NT_STATUS_INVALID_HANDLE;
661 : }
662 :
663 1399 : state = talloc(req, struct ipc_write_state);
664 1399 : NT_STATUS_HAVE_NO_MEMORY(state);
665 :
666 1399 : state->ipriv = ipriv;
667 1399 : state->p = p;
668 1399 : state->req = req;
669 1399 : state->wr = wr;
670 1399 : state->iov.iov_base = discard_const_p(void, wr->writex.in.data);
671 1399 : state->iov.iov_len = wr->writex.in.count;
672 :
673 1399 : subreq = tstream_writev_queue_send(state,
674 1399 : ipriv->ntvfs->ctx->event_ctx,
675 : p->npipe,
676 : p->write_queue,
677 1399 : &state->iov, 1);
678 1399 : NT_STATUS_HAVE_NO_MEMORY(subreq);
679 1399 : tevent_req_set_callback(subreq, ipc_write_done, state);
680 :
681 1399 : req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
682 1399 : return NT_STATUS_OK;
683 : }
684 :
685 1399 : static void ipc_write_done(struct tevent_req *subreq)
686 : {
687 0 : struct ipc_write_state *state =
688 1399 : tevent_req_callback_data(subreq,
689 : struct ipc_write_state);
690 1399 : struct ntvfs_request *req = state->req;
691 1399 : union smb_write *wr = state->wr;
692 0 : int ret;
693 0 : int sys_errno;
694 0 : NTSTATUS status;
695 :
696 1399 : ret = tstream_writev_queue_recv(subreq, &sys_errno);
697 1399 : TALLOC_FREE(subreq);
698 1399 : if (ret == -1) {
699 0 : status = map_nt_error_from_unix_common(sys_errno);
700 0 : goto reply;
701 : }
702 :
703 1399 : status = NT_STATUS_OK;
704 :
705 1399 : wr->writex.out.nwritten = ret;
706 1399 : wr->writex.out.remaining = 0;
707 :
708 1399 : reply:
709 1399 : req->async_states->status = status;
710 1399 : req->async_states->send_fn(req);
711 1399 : }
712 :
713 : /*
714 : seek in a file
715 : */
716 0 : static NTSTATUS ipc_seek(struct ntvfs_module_context *ntvfs,
717 : struct ntvfs_request *req,
718 : union smb_seek *io)
719 : {
720 0 : return NT_STATUS_ACCESS_DENIED;
721 : }
722 :
723 : /*
724 : flush a file
725 : */
726 0 : static NTSTATUS ipc_flush(struct ntvfs_module_context *ntvfs,
727 : struct ntvfs_request *req,
728 : union smb_flush *io)
729 : {
730 0 : return NT_STATUS_ACCESS_DENIED;
731 : }
732 :
733 : /*
734 : close a file
735 : */
736 2374 : static NTSTATUS ipc_close(struct ntvfs_module_context *ntvfs,
737 : struct ntvfs_request *req, union smb_close *io)
738 : {
739 2374 : struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
740 : struct ipc_private);
741 0 : struct pipe_state *p;
742 :
743 2374 : if (io->generic.level != RAW_CLOSE_GENERIC) {
744 1187 : return ntvfs_map_close(ntvfs, req, io);
745 : }
746 :
747 1187 : ZERO_STRUCT(io->generic.out);
748 :
749 1187 : p = pipe_state_find(ipriv, io->generic.in.file.ntvfs);
750 1187 : if (!p) {
751 0 : return NT_STATUS_INVALID_HANDLE;
752 : }
753 :
754 1187 : talloc_free(p);
755 :
756 1187 : return NT_STATUS_OK;
757 : }
758 :
759 : /*
760 : exit - closing files
761 : */
762 0 : static NTSTATUS ipc_exit(struct ntvfs_module_context *ntvfs,
763 : struct ntvfs_request *req)
764 : {
765 0 : struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
766 : struct ipc_private);
767 0 : struct pipe_state *p, *next;
768 :
769 0 : for (p=ipriv->pipe_list; p; p=next) {
770 0 : next = p->next;
771 0 : if (p->handle->session_info == req->session_info &&
772 0 : p->handle->smbpid == req->smbpid) {
773 0 : talloc_free(p);
774 : }
775 : }
776 :
777 0 : return NT_STATUS_OK;
778 : }
779 :
780 : /*
781 : logoff - closing files open by the user
782 : */
783 0 : static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs,
784 : struct ntvfs_request *req)
785 : {
786 0 : struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
787 : struct ipc_private);
788 0 : struct pipe_state *p, *next;
789 :
790 0 : for (p=ipriv->pipe_list; p; p=next) {
791 0 : next = p->next;
792 0 : if (p->handle->session_info == req->session_info) {
793 0 : talloc_free(p);
794 : }
795 : }
796 :
797 0 : return NT_STATUS_OK;
798 : }
799 :
800 : /*
801 : setup for an async call
802 : */
803 0 : static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
804 : struct ntvfs_request *req,
805 : void *private_data)
806 : {
807 0 : return NT_STATUS_OK;
808 : }
809 :
810 : /*
811 : cancel an async call
812 : */
813 0 : static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs,
814 : struct ntvfs_request *req)
815 : {
816 0 : return NT_STATUS_UNSUCCESSFUL;
817 : }
818 :
819 : /*
820 : lock a byte range
821 : */
822 0 : static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
823 : struct ntvfs_request *req, union smb_lock *lck)
824 : {
825 0 : return NT_STATUS_ACCESS_DENIED;
826 : }
827 :
828 : /*
829 : set info on a open file
830 : */
831 0 : static NTSTATUS ipc_setfileinfo(struct ntvfs_module_context *ntvfs,
832 : struct ntvfs_request *req, union smb_setfileinfo *info)
833 : {
834 0 : return NT_STATUS_ACCESS_DENIED;
835 : }
836 :
837 : /*
838 : query info on a open file
839 : */
840 49 : static NTSTATUS ipc_qfileinfo(struct ntvfs_module_context *ntvfs,
841 : struct ntvfs_request *req, union smb_fileinfo *info)
842 : {
843 49 : struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
844 : struct ipc_private);
845 49 : struct pipe_state *p = pipe_state_find(ipriv, info->generic.in.file.ntvfs);
846 49 : if (!p) {
847 0 : return NT_STATUS_INVALID_HANDLE;
848 : }
849 49 : switch (info->generic.level) {
850 20 : case RAW_FILEINFO_GENERIC:
851 : {
852 20 : ZERO_STRUCT(info->generic.out);
853 20 : info->generic.out.attrib = FILE_ATTRIBUTE_NORMAL;
854 20 : info->generic.out.fname.s = strrchr(p->pipe_name, '\\');
855 20 : info->generic.out.alloc_size = 4096;
856 20 : info->generic.out.nlink = 1;
857 : /* What the heck? Match Win2k3: IPC$ pipes are delete pending */
858 20 : info->generic.out.delete_pending = 1;
859 20 : return NT_STATUS_OK;
860 : }
861 8 : case RAW_FILEINFO_ALT_NAME_INFO:
862 : case RAW_FILEINFO_ALT_NAME_INFORMATION:
863 : case RAW_FILEINFO_STREAM_INFO:
864 : case RAW_FILEINFO_STREAM_INFORMATION:
865 : case RAW_FILEINFO_COMPRESSION_INFO:
866 : case RAW_FILEINFO_COMPRESSION_INFORMATION:
867 : case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
868 : case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
869 8 : return NT_STATUS_INVALID_PARAMETER;
870 1 : case RAW_FILEINFO_ALL_EAS:
871 1 : return NT_STATUS_ACCESS_DENIED;
872 20 : default:
873 20 : return ntvfs_map_qfileinfo(ntvfs, req, info);
874 : }
875 : }
876 :
877 :
878 : /*
879 : return filesystem info
880 : */
881 0 : static NTSTATUS ipc_fsinfo(struct ntvfs_module_context *ntvfs,
882 : struct ntvfs_request *req, union smb_fsinfo *fs)
883 : {
884 0 : return NT_STATUS_ACCESS_DENIED;
885 : }
886 :
887 : /*
888 : return print queue info
889 : */
890 0 : static NTSTATUS ipc_lpq(struct ntvfs_module_context *ntvfs,
891 : struct ntvfs_request *req, union smb_lpq *lpq)
892 : {
893 0 : return NT_STATUS_ACCESS_DENIED;
894 : }
895 :
896 : /*
897 : list files in a directory matching a wildcard pattern
898 : */
899 0 : static NTSTATUS ipc_search_first(struct ntvfs_module_context *ntvfs,
900 : struct ntvfs_request *req, union smb_search_first *io,
901 : void *search_private,
902 : bool (*callback)(void *, const union smb_search_data *))
903 : {
904 0 : return NT_STATUS_ACCESS_DENIED;
905 : }
906 :
907 : /*
908 : continue listing files in a directory
909 : */
910 0 : static NTSTATUS ipc_search_next(struct ntvfs_module_context *ntvfs,
911 : struct ntvfs_request *req, union smb_search_next *io,
912 : void *search_private,
913 : bool (*callback)(void *, const union smb_search_data *))
914 : {
915 0 : return NT_STATUS_ACCESS_DENIED;
916 : }
917 :
918 : /*
919 : end listing files in a directory
920 : */
921 0 : static NTSTATUS ipc_search_close(struct ntvfs_module_context *ntvfs,
922 : struct ntvfs_request *req, union smb_search_close *io)
923 : {
924 0 : return NT_STATUS_ACCESS_DENIED;
925 : }
926 :
927 : struct ipc_trans_state {
928 : struct ipc_private *ipriv;
929 : struct pipe_state *p;
930 : struct ntvfs_request *req;
931 : struct smb_trans2 *trans;
932 : struct iovec writev_iov;
933 : struct ipc_readv_next_vector_state next_vector;
934 : };
935 :
936 : static void ipc_trans_writev_done(struct tevent_req *subreq);
937 : static void ipc_trans_readv_done(struct tevent_req *subreq);
938 :
939 : /* SMBtrans - handle a DCERPC command */
940 42 : static NTSTATUS ipc_dcerpc_cmd(struct ntvfs_module_context *ntvfs,
941 : struct ntvfs_request *req, struct smb_trans2 *trans)
942 : {
943 42 : struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
944 : struct ipc_private);
945 0 : struct pipe_state *p;
946 0 : DATA_BLOB fnum_key;
947 0 : uint16_t fnum;
948 0 : struct ipc_trans_state *state;
949 0 : struct tevent_req *subreq;
950 :
951 : /*
952 : * the fnum is in setup[1], a 16 bit value
953 : * the setup[*] values are already in host byteorder
954 : * but ntvfs_handle_search_by_wire_key() expects
955 : * network byteorder
956 : */
957 42 : SSVAL(&fnum, 0, trans->in.setup[1]);
958 42 : fnum_key = data_blob_const(&fnum, 2);
959 :
960 42 : p = pipe_state_find_key(ipriv, req, &fnum_key);
961 42 : if (!p) {
962 9 : return NT_STATUS_INVALID_HANDLE;
963 : }
964 :
965 : /*
966 : * Trans requests are only allowed
967 : * if no other Trans or Read is active
968 : */
969 33 : if (tevent_queue_length(p->read_queue) > 0) {
970 0 : return NT_STATUS_PIPE_BUSY;
971 : }
972 :
973 33 : state = talloc(req, struct ipc_trans_state);
974 33 : NT_STATUS_HAVE_NO_MEMORY(state);
975 :
976 33 : trans->out.setup_count = 0;
977 33 : trans->out.setup = NULL;
978 33 : trans->out.params = data_blob(NULL, 0);
979 33 : trans->out.data = data_blob_talloc(req, NULL, trans->in.max_data);
980 33 : NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
981 :
982 33 : state->ipriv = ipriv;
983 33 : state->p = p;
984 33 : state->req = req;
985 33 : state->trans = trans;
986 33 : state->writev_iov.iov_base = (char *) trans->in.data.data;
987 33 : state->writev_iov.iov_len = trans->in.data.length;
988 :
989 33 : ipc_readv_next_vector_init(&state->next_vector,
990 : trans->out.data.data,
991 : trans->out.data.length);
992 :
993 33 : subreq = tstream_writev_queue_send(state,
994 33 : ipriv->ntvfs->ctx->event_ctx,
995 : p->npipe,
996 : p->write_queue,
997 33 : &state->writev_iov, 1);
998 33 : NT_STATUS_HAVE_NO_MEMORY(subreq);
999 33 : tevent_req_set_callback(subreq, ipc_trans_writev_done, state);
1000 :
1001 33 : req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1002 33 : return NT_STATUS_OK;
1003 : }
1004 :
1005 33 : static void ipc_trans_writev_done(struct tevent_req *subreq)
1006 : {
1007 0 : struct ipc_trans_state *state =
1008 33 : tevent_req_callback_data(subreq,
1009 : struct ipc_trans_state);
1010 33 : struct ipc_private *ipriv = state->ipriv;
1011 33 : struct pipe_state *p = state->p;
1012 33 : struct ntvfs_request *req = state->req;
1013 0 : int ret;
1014 0 : int sys_errno;
1015 0 : NTSTATUS status;
1016 :
1017 33 : ret = tstream_writev_queue_recv(subreq, &sys_errno);
1018 33 : TALLOC_FREE(subreq);
1019 33 : if (ret == 0) {
1020 0 : status = NT_STATUS_PIPE_DISCONNECTED;
1021 0 : goto reply;
1022 33 : } else if (ret == -1) {
1023 0 : status = map_nt_error_from_unix_common(sys_errno);
1024 0 : goto reply;
1025 : }
1026 :
1027 33 : subreq = tstream_readv_pdu_queue_send(state,
1028 33 : ipriv->ntvfs->ctx->event_ctx,
1029 : p->npipe,
1030 : p->read_queue,
1031 : ipc_readv_next_vector,
1032 33 : &state->next_vector);
1033 33 : if (!subreq) {
1034 0 : status = NT_STATUS_NO_MEMORY;
1035 0 : goto reply;
1036 : }
1037 33 : tevent_req_set_callback(subreq, ipc_trans_readv_done, state);
1038 33 : return;
1039 :
1040 0 : reply:
1041 0 : req->async_states->status = status;
1042 0 : req->async_states->send_fn(req);
1043 : }
1044 :
1045 33 : static void ipc_trans_readv_done(struct tevent_req *subreq)
1046 : {
1047 0 : struct ipc_trans_state *state =
1048 33 : tevent_req_callback_data(subreq,
1049 : struct ipc_trans_state);
1050 33 : struct ntvfs_request *req = state->req;
1051 33 : struct smb_trans2 *trans = state->trans;
1052 0 : int ret;
1053 0 : int sys_errno;
1054 0 : NTSTATUS status;
1055 :
1056 33 : ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1057 33 : TALLOC_FREE(subreq);
1058 33 : if (ret == -1) {
1059 0 : status = map_nt_error_from_unix_common(sys_errno);
1060 0 : goto reply;
1061 : }
1062 :
1063 33 : status = NT_STATUS_OK;
1064 33 : if (state->next_vector.remaining > 0) {
1065 0 : status = STATUS_BUFFER_OVERFLOW;
1066 : }
1067 :
1068 33 : trans->out.data.length = ret;
1069 :
1070 33 : reply:
1071 33 : req->async_states->status = status;
1072 33 : req->async_states->send_fn(req);
1073 33 : }
1074 :
1075 : /* SMBtrans - set named pipe state */
1076 0 : static NTSTATUS ipc_set_nm_pipe_state(struct ntvfs_module_context *ntvfs,
1077 : struct ntvfs_request *req, struct smb_trans2 *trans)
1078 : {
1079 0 : struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1080 : struct ipc_private);
1081 0 : struct pipe_state *p;
1082 0 : DATA_BLOB fnum_key;
1083 :
1084 : /* the fnum is in setup[1] */
1085 0 : fnum_key = data_blob_const(&trans->in.setup[1], sizeof(trans->in.setup[1]));
1086 :
1087 0 : p = pipe_state_find_key(ipriv, req, &fnum_key);
1088 0 : if (!p) {
1089 0 : return NT_STATUS_INVALID_HANDLE;
1090 : }
1091 :
1092 0 : if (trans->in.params.length != 2) {
1093 0 : return NT_STATUS_INVALID_PARAMETER;
1094 : }
1095 :
1096 : /*
1097 : * TODO: pass this to the tstream_npa logic
1098 : */
1099 0 : p->device_state = SVAL(trans->in.params.data, 0);
1100 :
1101 0 : trans->out.setup_count = 0;
1102 0 : trans->out.setup = NULL;
1103 0 : trans->out.params = data_blob(NULL, 0);
1104 0 : trans->out.data = data_blob(NULL, 0);
1105 :
1106 0 : return NT_STATUS_OK;
1107 : }
1108 :
1109 :
1110 : /* SMBtrans - used to provide access to SMB pipes */
1111 42 : static NTSTATUS ipc_trans(struct ntvfs_module_context *ntvfs,
1112 : struct ntvfs_request *req, struct smb_trans2 *trans)
1113 : {
1114 0 : NTSTATUS status;
1115 :
1116 42 : if (strequal(trans->in.trans_name, "\\PIPE\\LANMAN"))
1117 0 : return ipc_rap_call(req, ntvfs->ctx->event_ctx, ntvfs->ctx->lp_ctx, trans);
1118 :
1119 42 : if (trans->in.setup_count != 2) {
1120 0 : return NT_STATUS_INVALID_PARAMETER;
1121 : }
1122 :
1123 42 : switch (trans->in.setup[0]) {
1124 0 : case TRANSACT_SETNAMEDPIPEHANDLESTATE:
1125 0 : status = ipc_set_nm_pipe_state(ntvfs, req, trans);
1126 0 : break;
1127 42 : case TRANSACT_DCERPCCMD:
1128 42 : status = ipc_dcerpc_cmd(ntvfs, req, trans);
1129 42 : break;
1130 0 : default:
1131 0 : status = NT_STATUS_INVALID_PARAMETER;
1132 0 : break;
1133 : }
1134 :
1135 42 : return status;
1136 : }
1137 :
1138 : struct ipc_ioctl_state {
1139 : struct ipc_private *ipriv;
1140 : struct pipe_state *p;
1141 : struct ntvfs_request *req;
1142 : union smb_ioctl *io;
1143 : struct iovec writev_iov;
1144 : struct ipc_readv_next_vector_state next_vector;
1145 : };
1146 :
1147 : static void ipc_ioctl_writev_done(struct tevent_req *subreq);
1148 : static void ipc_ioctl_readv_done(struct tevent_req *subreq);
1149 :
1150 47488 : static NTSTATUS ipc_ioctl_smb2(struct ntvfs_module_context *ntvfs,
1151 : struct ntvfs_request *req, union smb_ioctl *io)
1152 : {
1153 47488 : struct ipc_private *ipriv = talloc_get_type_abort(ntvfs->private_data,
1154 : struct ipc_private);
1155 0 : struct pipe_state *p;
1156 0 : struct ipc_ioctl_state *state;
1157 0 : struct tevent_req *subreq;
1158 :
1159 47488 : switch (io->smb2.in.function) {
1160 47488 : case FSCTL_NAMED_PIPE_READ_WRITE:
1161 47488 : break;
1162 :
1163 0 : default:
1164 0 : return NT_STATUS_FS_DRIVER_REQUIRED;
1165 : }
1166 :
1167 47488 : p = pipe_state_find(ipriv, io->smb2.in.file.ntvfs);
1168 47488 : if (!p) {
1169 0 : return NT_STATUS_INVALID_HANDLE;
1170 : }
1171 :
1172 : /*
1173 : * Trans requests are only allowed
1174 : * if no other Trans or Read is active
1175 : */
1176 47488 : if (tevent_queue_length(p->read_queue) > 0) {
1177 0 : return NT_STATUS_PIPE_BUSY;
1178 : }
1179 :
1180 47488 : state = talloc(req, struct ipc_ioctl_state);
1181 47488 : NT_STATUS_HAVE_NO_MEMORY(state);
1182 :
1183 47488 : io->smb2.out.reserved = 0;
1184 47488 : io->smb2.out.function = io->smb2.in.function;
1185 47488 : io->smb2.out.flags = 0;
1186 47488 : io->smb2.out.reserved2 = 0;
1187 47488 : io->smb2.out.in = data_blob_null;
1188 47488 : io->smb2.out.out = data_blob_talloc(req, NULL, io->smb2.in.max_output_response);
1189 47488 : NT_STATUS_HAVE_NO_MEMORY(io->smb2.out.out.data);
1190 :
1191 47488 : state->ipriv = ipriv;
1192 47488 : state->p = p;
1193 47488 : state->req = req;
1194 47488 : state->io = io;
1195 47488 : state->writev_iov.iov_base = (char *) io->smb2.in.out.data;
1196 47488 : state->writev_iov.iov_len = io->smb2.in.out.length;
1197 :
1198 47488 : ipc_readv_next_vector_init(&state->next_vector,
1199 : io->smb2.out.out.data,
1200 : io->smb2.out.out.length);
1201 :
1202 47488 : subreq = tstream_writev_queue_send(state,
1203 47488 : ipriv->ntvfs->ctx->event_ctx,
1204 : p->npipe,
1205 : p->write_queue,
1206 47488 : &state->writev_iov, 1);
1207 47488 : NT_STATUS_HAVE_NO_MEMORY(subreq);
1208 47488 : tevent_req_set_callback(subreq, ipc_ioctl_writev_done, state);
1209 :
1210 47488 : req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1211 47488 : return NT_STATUS_OK;
1212 : }
1213 :
1214 47488 : static void ipc_ioctl_writev_done(struct tevent_req *subreq)
1215 : {
1216 0 : struct ipc_ioctl_state *state =
1217 47488 : tevent_req_callback_data(subreq,
1218 : struct ipc_ioctl_state);
1219 47488 : struct ipc_private *ipriv = state->ipriv;
1220 47488 : struct pipe_state *p = state->p;
1221 47488 : struct ntvfs_request *req = state->req;
1222 0 : int ret;
1223 0 : int sys_errno;
1224 0 : NTSTATUS status;
1225 :
1226 47488 : ret = tstream_writev_queue_recv(subreq, &sys_errno);
1227 47488 : TALLOC_FREE(subreq);
1228 47488 : if (ret == -1) {
1229 0 : status = map_nt_error_from_unix_common(sys_errno);
1230 0 : goto reply;
1231 : }
1232 :
1233 47488 : subreq = tstream_readv_pdu_queue_send(state,
1234 47488 : ipriv->ntvfs->ctx->event_ctx,
1235 : p->npipe,
1236 : p->read_queue,
1237 : ipc_readv_next_vector,
1238 47488 : &state->next_vector);
1239 47488 : if (!subreq) {
1240 0 : status = NT_STATUS_NO_MEMORY;
1241 0 : goto reply;
1242 : }
1243 47488 : tevent_req_set_callback(subreq, ipc_ioctl_readv_done, state);
1244 47488 : return;
1245 :
1246 0 : reply:
1247 0 : req->async_states->status = status;
1248 0 : req->async_states->send_fn(req);
1249 : }
1250 :
1251 47488 : static void ipc_ioctl_readv_done(struct tevent_req *subreq)
1252 : {
1253 0 : struct ipc_ioctl_state *state =
1254 47488 : tevent_req_callback_data(subreq,
1255 : struct ipc_ioctl_state);
1256 47488 : struct ntvfs_request *req = state->req;
1257 47488 : union smb_ioctl *io = state->io;
1258 0 : int ret;
1259 0 : int sys_errno;
1260 0 : NTSTATUS status;
1261 :
1262 47488 : ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1263 47488 : TALLOC_FREE(subreq);
1264 47488 : if (ret == -1) {
1265 0 : status = map_nt_error_from_unix_common(sys_errno);
1266 0 : goto reply;
1267 : }
1268 :
1269 47488 : status = NT_STATUS_OK;
1270 47488 : if (state->next_vector.remaining > 0) {
1271 0 : status = STATUS_BUFFER_OVERFLOW;
1272 : }
1273 :
1274 47488 : io->smb2.out.out.length = ret;
1275 :
1276 47488 : reply:
1277 47488 : req->async_states->status = status;
1278 47488 : req->async_states->send_fn(req);
1279 47488 : }
1280 :
1281 : /*
1282 : ioctl interface
1283 : */
1284 48476 : static NTSTATUS ipc_ioctl(struct ntvfs_module_context *ntvfs,
1285 : struct ntvfs_request *req, union smb_ioctl *io)
1286 : {
1287 48476 : switch (io->generic.level) {
1288 47488 : case RAW_IOCTL_SMB2:
1289 47488 : return ipc_ioctl_smb2(ntvfs, req, io);
1290 :
1291 988 : case RAW_IOCTL_SMB2_NO_HANDLE:
1292 988 : return NT_STATUS_FS_DRIVER_REQUIRED;
1293 :
1294 0 : default:
1295 0 : return NT_STATUS_ACCESS_DENIED;
1296 : }
1297 : }
1298 :
1299 :
1300 : /*
1301 : initialise the IPC backend, registering ourselves with the ntvfs subsystem
1302 : */
1303 68 : NTSTATUS ntvfs_ipc_init(TALLOC_CTX *ctx)
1304 : {
1305 3 : NTSTATUS ret;
1306 3 : struct ntvfs_ops ops;
1307 68 : NTVFS_CURRENT_CRITICAL_SIZES(vers);
1308 :
1309 68 : ZERO_STRUCT(ops);
1310 :
1311 : /* fill in the name and type */
1312 68 : ops.name = "default";
1313 68 : ops.type = NTVFS_IPC;
1314 :
1315 : /* fill in all the operations */
1316 68 : ops.connect_fn = ipc_connect;
1317 68 : ops.disconnect_fn = ipc_disconnect;
1318 68 : ops.unlink_fn = ipc_unlink;
1319 68 : ops.chkpath_fn = ipc_chkpath;
1320 68 : ops.qpathinfo_fn = ipc_qpathinfo;
1321 68 : ops.setpathinfo_fn = ipc_setpathinfo;
1322 68 : ops.open_fn = ipc_open;
1323 68 : ops.mkdir_fn = ipc_mkdir;
1324 68 : ops.rmdir_fn = ipc_rmdir;
1325 68 : ops.rename_fn = ipc_rename;
1326 68 : ops.copy_fn = ipc_copy;
1327 68 : ops.ioctl_fn = ipc_ioctl;
1328 68 : ops.read_fn = ipc_read;
1329 68 : ops.write_fn = ipc_write;
1330 68 : ops.seek_fn = ipc_seek;
1331 68 : ops.flush_fn = ipc_flush;
1332 68 : ops.close_fn = ipc_close;
1333 68 : ops.exit_fn = ipc_exit;
1334 68 : ops.lock_fn = ipc_lock;
1335 68 : ops.setfileinfo_fn = ipc_setfileinfo;
1336 68 : ops.qfileinfo_fn = ipc_qfileinfo;
1337 68 : ops.fsinfo_fn = ipc_fsinfo;
1338 68 : ops.lpq_fn = ipc_lpq;
1339 68 : ops.search_first_fn = ipc_search_first;
1340 68 : ops.search_next_fn = ipc_search_next;
1341 68 : ops.search_close_fn = ipc_search_close;
1342 68 : ops.trans_fn = ipc_trans;
1343 68 : ops.logoff_fn = ipc_logoff;
1344 68 : ops.async_setup_fn = ipc_async_setup;
1345 68 : ops.cancel_fn = ipc_cancel;
1346 :
1347 : /* register ourselves with the NTVFS subsystem. */
1348 68 : ret = ntvfs_register(&ops, &vers);
1349 :
1350 68 : if (!NT_STATUS_IS_OK(ret)) {
1351 0 : DEBUG(0,("Failed to register IPC backend!\n"));
1352 0 : return ret;
1353 : }
1354 :
1355 68 : return ret;
1356 : }
|