• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/ntvfs/smb2/
1/*
2   Unix SMB/CIFS implementation.
3
4   CIFS-to-SMB2 NTVFS filesystem backend
5
6   Copyright (C) Andrew Tridgell 2008
7
8   largely based on vfs_cifs.c which was
9      Copyright (C) Andrew Tridgell 2003
10      Copyright (C) James J Myers 2003 <myersjj@samba.org>
11
12   This program is free software; you can redistribute it and/or modify
13   it under the terms of the GNU General Public License as published by
14   the Free Software Foundation; either version 3 of the License, or
15   (at your option) any later version.
16
17   This program is distributed in the hope that it will be useful,
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20   GNU General Public License for more details.
21
22   You should have received a copy of the GNU General Public License
23   along with this program.  If not, see <http://www.gnu.org/licenses/>.
24*/
25/*
26  this implements a CIFS->CIFS NTVFS filesystem backend.
27
28*/
29
30#include "includes.h"
31#include "libcli/raw/libcliraw.h"
32#include "libcli/raw/raw_proto.h"
33#include "libcli/composite/composite.h"
34#include "libcli/smb_composite/smb_composite.h"
35#include "auth/auth.h"
36#include "auth/credentials/credentials.h"
37#include "ntvfs/ntvfs.h"
38#include "../lib/util/dlinklist.h"
39#include "param/param.h"
40#include "libcli/resolve/resolve.h"
41#include "libcli/smb2/smb2.h"
42#include "libcli/smb2/smb2_calls.h"
43
44struct cvfs_file {
45	struct cvfs_file *prev, *next;
46	uint16_t fnum;
47	struct ntvfs_handle *h;
48};
49
50/* this is stored in ntvfs_private */
51struct cvfs_private {
52	struct smb2_tree *tree;
53	struct smb2_transport *transport;
54	struct ntvfs_module_context *ntvfs;
55	struct async_info *pending;
56	struct cvfs_file *files;
57
58	/* a handle on the root of the share */
59	/* TODO: leaving this handle open could prevent other users
60	   from opening the share with exclusive access. We probably
61	   need to open it on demand */
62	struct smb2_handle roothandle;
63};
64
65
66/* a structure used to pass information to an async handler */
67struct async_info {
68	struct async_info *next, *prev;
69	struct cvfs_private *cvfs;
70	struct ntvfs_request *req;
71	void *c_req;
72	struct composite_context *c_comp;
73	struct cvfs_file *f;
74	void *parms;
75};
76
77#define SETUP_FILE_HERE(f) do { \
78	f = ntvfs_handle_get_backend_data(io->generic.in.file.ntvfs, ntvfs); \
79	if (!f) return NT_STATUS_INVALID_HANDLE; \
80	io->generic.in.file.fnum = f->fnum; \
81} while (0)
82
83#define SETUP_FILE do { \
84	struct cvfs_file *f; \
85	SETUP_FILE_HERE(f); \
86} while (0)
87
88#define SMB2_SERVER		"smb2:server"
89#define SMB2_USER		"smb2:user"
90#define SMB2_PASSWORD		"smb2:password"
91#define SMB2_DOMAIN		"smb2:domain"
92#define SMB2_SHARE		"smb2:share"
93#define SMB2_USE_MACHINE_ACCT	"smb2:use-machine-account"
94
95#define SMB2_USE_MACHINE_ACCT_DEFAULT	false
96
97/*
98  a handler for oplock break events from the server - these need to be passed
99  along to the client
100 */
101static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
102{
103	struct cvfs_private *p = p_private;
104	NTSTATUS status;
105	struct ntvfs_handle *h = NULL;
106	struct cvfs_file *f;
107
108	for (f=p->files; f; f=f->next) {
109		if (f->fnum != fnum) continue;
110		h = f->h;
111		break;
112	}
113
114	if (!h) {
115		DEBUG(5,("vfs_smb2: ignoring oplock break level %d for fnum %d\n", level, fnum));
116		return true;
117	}
118
119	DEBUG(5,("vfs_smb2: sending oplock break level %d for fnum %d\n", level, fnum));
120	status = ntvfs_send_oplock_break(p->ntvfs, h, level);
121	if (!NT_STATUS_IS_OK(status)) return false;
122	return true;
123}
124
125/*
126  return a handle to the root of the share
127*/
128static NTSTATUS smb2_get_roothandle(struct smb2_tree *tree, struct smb2_handle *handle)
129{
130	struct smb2_create io;
131	NTSTATUS status;
132
133	ZERO_STRUCT(io);
134	io.in.oplock_level = 0;
135	io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
136	io.in.file_attributes   = 0;
137	io.in.create_disposition = NTCREATEX_DISP_OPEN;
138	io.in.share_access =
139		NTCREATEX_SHARE_ACCESS_READ |
140		NTCREATEX_SHARE_ACCESS_WRITE|
141		NTCREATEX_SHARE_ACCESS_DELETE;
142	io.in.create_options = 0;
143	io.in.fname = NULL;
144
145	status = smb2_create(tree, tree, &io);
146	NT_STATUS_NOT_OK_RETURN(status);
147
148	*handle = io.out.file.handle;
149
150	return NT_STATUS_OK;
151}
152
153/*
154  connect to a share - used when a tree_connect operation comes in.
155*/
156static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
157			     struct ntvfs_request *req,
158			     union smb_tcon* tcon)
159{
160	NTSTATUS status;
161	struct cvfs_private *p;
162	const char *host, *user, *pass, *domain, *remote_share, *sharename;
163	struct composite_context *creq;
164	struct share_config *scfg = ntvfs->ctx->config;
165	struct smb2_tree *tree;
166	struct cli_credentials *credentials;
167	bool machine_account;
168	struct smbcli_options options;
169
170	switch (tcon->generic.level) {
171	case RAW_TCON_TCON:
172		sharename = tcon->tcon.in.service;
173		break;
174	case RAW_TCON_TCONX:
175		sharename = tcon->tconx.in.path;
176		break;
177	case RAW_TCON_SMB2:
178		sharename = tcon->smb2.in.path;
179		break;
180	default:
181		return NT_STATUS_INVALID_LEVEL;
182	}
183
184	if (strncmp(sharename, "\\\\", 2) == 0) {
185		char *str = strchr(sharename+2, '\\');
186		if (str) {
187			sharename = str + 1;
188		}
189	}
190
191	/* Here we need to determine which server to connect to.
192	 * For now we use parametric options, type cifs.
193	 * Later we will use security=server and auth_server.c.
194	 */
195	host = share_string_option(scfg, SMB2_SERVER, NULL);
196	user = share_string_option(scfg, SMB2_USER, NULL);
197	pass = share_string_option(scfg, SMB2_PASSWORD, NULL);
198	domain = share_string_option(scfg, SMB2_DOMAIN, NULL);
199	remote_share = share_string_option(scfg, SMB2_SHARE, NULL);
200	if (!remote_share) {
201		remote_share = sharename;
202	}
203
204	machine_account = share_bool_option(scfg, SMB2_USE_MACHINE_ACCT, SMB2_USE_MACHINE_ACCT_DEFAULT);
205
206	p = talloc_zero(ntvfs, struct cvfs_private);
207	if (!p) {
208		return NT_STATUS_NO_MEMORY;
209	}
210
211	ntvfs->private_data = p;
212
213	if (!host) {
214		DEBUG(1,("CIFS backend: You must supply server\n"));
215		return NT_STATUS_INVALID_PARAMETER;
216	}
217
218	if (user && pass) {
219		DEBUG(5, ("CIFS backend: Using specified password\n"));
220		credentials = cli_credentials_init(p);
221		if (!credentials) {
222			return NT_STATUS_NO_MEMORY;
223		}
224		cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx);
225		cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
226		if (domain) {
227			cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
228		}
229		cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
230	} else if (machine_account) {
231		DEBUG(5, ("CIFS backend: Using machine account\n"));
232		credentials = cli_credentials_init(p);
233		cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx);
234		if (domain) {
235			cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
236		}
237		status = cli_credentials_set_machine_account(credentials, ntvfs->ctx->lp_ctx);
238		if (!NT_STATUS_IS_OK(status)) {
239			return status;
240		}
241	} else if (req->session_info->credentials) {
242		DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
243		credentials = req->session_info->credentials;
244	} else {
245		DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
246		return NT_STATUS_INVALID_PARAMETER;
247	}
248
249	lp_smbcli_options(ntvfs->ctx->lp_ctx, &options);
250
251	creq = smb2_connect_send(p, host,
252			lp_parm_string_list(p, ntvfs->ctx->lp_ctx, NULL, "smb2", "ports", NULL),
253				remote_share,
254				 lp_resolve_context(ntvfs->ctx->lp_ctx),
255				 credentials,
256				 ntvfs->ctx->event_ctx, &options,
257				 lp_socket_options(ntvfs->ctx->lp_ctx),
258				 lp_gensec_settings(p, ntvfs->ctx->lp_ctx)
259				 );
260
261	status = smb2_connect_recv(creq, p, &tree);
262	NT_STATUS_NOT_OK_RETURN(status);
263
264	status = smb2_get_roothandle(tree, &p->roothandle);
265	NT_STATUS_NOT_OK_RETURN(status);
266
267	p->tree = tree;
268	p->transport = p->tree->session->transport;
269	p->ntvfs = ntvfs;
270
271	ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
272	NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
273	ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
274	NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
275
276	if (tcon->generic.level == RAW_TCON_TCONX) {
277		tcon->tconx.out.fs_type = ntvfs->ctx->fs_type;
278		tcon->tconx.out.dev_type = ntvfs->ctx->dev_type;
279	}
280
281	/* we need to receive oplock break requests from the server */
282	/* TODO: enable oplocks
283	smbcli_oplock_handler(p->transport, oplock_handler, p);
284	*/
285	return NT_STATUS_OK;
286}
287
288/*
289  disconnect from a share
290*/
291static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs)
292{
293	struct cvfs_private *p = ntvfs->private_data;
294	struct async_info *a, *an;
295
296	/* first cleanup pending requests */
297	for (a=p->pending; a; a = an) {
298		an = a->next;
299		talloc_free(a->c_req);
300		talloc_free(a);
301	}
302
303	talloc_free(p);
304	ntvfs->private_data = NULL;
305
306	return NT_STATUS_OK;
307}
308
309/*
310  destroy an async info structure
311*/
312static int async_info_destructor(struct async_info *async)
313{
314	DLIST_REMOVE(async->cvfs->pending, async);
315	return 0;
316}
317
318/*
319  a handler for simple async SMB2 replies
320  this handler can only be used for functions that don't return any
321  parameters (those that just return a status code)
322 */
323static void async_simple_smb2(struct smb2_request *c_req)
324{
325	struct async_info *async = c_req->async.private_data;
326	struct ntvfs_request *req = async->req;
327
328	smb2_request_receive(c_req);
329	req->async_states->status = smb2_request_destroy(c_req);
330	talloc_free(async);
331	req->async_states->send_fn(req);
332}
333
334/*
335  a handler for simple async composite replies
336  this handler can only be used for functions that don't return any
337  parameters (those that just return a status code)
338 */
339static void async_simple_composite(struct composite_context *c_req)
340{
341	struct async_info *async = c_req->async.private_data;
342	struct ntvfs_request *req = async->req;
343
344	req->async_states->status = composite_wait_free(c_req);
345	talloc_free(async);
346	req->async_states->send_fn(req);
347}
348
349
350/* save some typing for the simple functions */
351#define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
352	if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
353	{ \
354		struct async_info *async; \
355		async = talloc(req, struct async_info); \
356		if (!async) return NT_STATUS_NO_MEMORY; \
357		async->parms = io; \
358		async->req = req; \
359		async->f = file; \
360		async->cvfs = p; \
361		async->c_req = c_req; \
362		DLIST_ADD(p->pending, async); \
363		c_req->async.private_data = async; \
364		talloc_set_destructor(async, async_info_destructor); \
365	} \
366	c_req->async.fn = async_fn; \
367	req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
368	return NT_STATUS_OK; \
369} while (0)
370
371#define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
372
373#define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple_smb2)
374#define SIMPLE_COMPOSITE_TAIL ASYNC_RECV_TAIL(NULL, async_simple_composite)
375
376#define CHECK_ASYNC(req) do { \
377	if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { \
378		DEBUG(0,("SMB2 proxy backend does not support sync operation at %s\n", \
379			 __location__)); \
380		return NT_STATUS_NOT_IMPLEMENTED; \
381	}} while (0)
382
383/*
384  delete a file - the dirtype specifies the file types to include in the search.
385  The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
386
387  BUGS:
388     - doesn't handle wildcards
389     - doesn't obey attrib restrictions
390*/
391static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs,
392			    struct ntvfs_request *req, union smb_unlink *unl)
393{
394	struct cvfs_private *p = ntvfs->private_data;
395	struct composite_context *c_req;
396
397	CHECK_ASYNC(req);
398
399	c_req = smb2_composite_unlink_send(p->tree, unl);
400
401	SIMPLE_COMPOSITE_TAIL;
402}
403
404/*
405  ioctl interface
406*/
407static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs,
408			   struct ntvfs_request *req, union smb_ioctl *io)
409{
410	return NT_STATUS_NOT_IMPLEMENTED;
411}
412
413/*
414  check if a directory exists
415*/
416static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs,
417			     struct ntvfs_request *req, union smb_chkpath *cp)
418{
419	struct cvfs_private *p = ntvfs->private_data;
420	struct smb2_request *c_req;
421	struct smb2_find f;
422
423	CHECK_ASYNC(req);
424
425	/* SMB2 doesn't have a chkpath operation, and also doesn't
426	 have a query path info call, so the best seems to be to do a
427	 find call, using the roothandle we established at connect
428	 time */
429	ZERO_STRUCT(f);
430	f.in.file.handle	= p->roothandle;
431	f.in.level              = SMB2_FIND_DIRECTORY_INFO;
432	f.in.pattern		= cp->chkpath.in.path;
433	/* SMB2 find doesn't accept \ or the empty string - this is the best
434	   approximation */
435	if (strcmp(f.in.pattern, "\\") == 0 ||
436	    strcmp(f.in.pattern, "") == 0) {
437		f.in.pattern		= "?";
438	}
439	f.in.continue_flags	= SMB2_CONTINUE_FLAG_SINGLE | SMB2_CONTINUE_FLAG_RESTART;
440	f.in.max_response_size	= 0x1000;
441
442	c_req = smb2_find_send(p->tree, &f);
443
444	SIMPLE_ASYNC_TAIL;
445}
446
447/*
448  return info on a pathname
449*/
450static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
451			       struct ntvfs_request *req, union smb_fileinfo *info)
452{
453	return NT_STATUS_NOT_IMPLEMENTED;
454}
455
456/*
457  query info on a open file
458*/
459static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
460			       struct ntvfs_request *req, union smb_fileinfo *io)
461{
462	return NT_STATUS_NOT_IMPLEMENTED;
463}
464
465
466/*
467  set info on a pathname
468*/
469static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
470				 struct ntvfs_request *req, union smb_setfileinfo *st)
471{
472	return NT_STATUS_NOT_IMPLEMENTED;
473}
474
475
476/*
477  open a file
478*/
479static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs,
480			  struct ntvfs_request *req, union smb_open *io)
481{
482	return NT_STATUS_NOT_IMPLEMENTED;
483}
484
485/*
486  create a directory
487*/
488static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs,
489			   struct ntvfs_request *req, union smb_mkdir *md)
490{
491	struct cvfs_private *p = ntvfs->private_data;
492	struct composite_context *c_req;
493
494	CHECK_ASYNC(req);
495
496	c_req = smb2_composite_mkdir_send(p->tree, md);
497
498	SIMPLE_COMPOSITE_TAIL;
499}
500
501/*
502  remove a directory
503*/
504static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs,
505			   struct ntvfs_request *req, struct smb_rmdir *rd)
506{
507	struct cvfs_private *p = ntvfs->private_data;
508	struct composite_context *c_req;
509
510	CHECK_ASYNC(req);
511
512	c_req = smb2_composite_rmdir_send(p->tree, rd);
513
514	SIMPLE_COMPOSITE_TAIL;
515}
516
517/*
518  rename a set of files
519*/
520static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs,
521			    struct ntvfs_request *req, union smb_rename *ren)
522{
523	return NT_STATUS_NOT_IMPLEMENTED;
524}
525
526/*
527  copy a set of files
528*/
529static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs,
530			  struct ntvfs_request *req, struct smb_copy *cp)
531{
532	return NT_STATUS_NOT_SUPPORTED;
533}
534
535/*
536  read from a file
537*/
538static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs,
539			  struct ntvfs_request *req, union smb_read *io)
540{
541	return NT_STATUS_NOT_IMPLEMENTED;
542}
543
544/*
545  write to a file
546*/
547static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs,
548			   struct ntvfs_request *req, union smb_write *io)
549{
550	return NT_STATUS_NOT_IMPLEMENTED;
551}
552
553/*
554  seek in a file
555*/
556static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs,
557			  struct ntvfs_request *req,
558			  union smb_seek *io)
559{
560	return NT_STATUS_NOT_IMPLEMENTED;
561}
562
563/*
564  flush a file
565*/
566static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs,
567			   struct ntvfs_request *req,
568			   union smb_flush *io)
569{
570	return NT_STATUS_NOT_IMPLEMENTED;
571}
572
573/*
574  close a file
575*/
576static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs,
577			   struct ntvfs_request *req, union smb_close *io)
578{
579	return NT_STATUS_NOT_IMPLEMENTED;
580}
581
582/*
583  exit - closing files open by the pid
584*/
585static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs,
586			  struct ntvfs_request *req)
587{
588	return NT_STATUS_NOT_IMPLEMENTED;
589}
590
591/*
592  logoff - closing files open by the user
593*/
594static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs,
595			    struct ntvfs_request *req)
596{
597	/* we can't do this right in the cifs backend .... */
598	return NT_STATUS_OK;
599}
600
601/*
602  setup for an async call - nothing to do yet
603*/
604static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs,
605				 struct ntvfs_request *req,
606				 void *private_data)
607{
608	return NT_STATUS_OK;
609}
610
611/*
612  cancel an async call
613*/
614static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs,
615			    struct ntvfs_request *req)
616{
617	return NT_STATUS_NOT_IMPLEMENTED;
618}
619
620/*
621  lock a byte range
622*/
623static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs,
624			  struct ntvfs_request *req, union smb_lock *io)
625{
626	return NT_STATUS_NOT_IMPLEMENTED;
627}
628
629/*
630  set info on a open file
631*/
632static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
633				 struct ntvfs_request *req,
634				 union smb_setfileinfo *io)
635{
636	return NT_STATUS_NOT_IMPLEMENTED;
637}
638
639
640/*
641  a handler for async fsinfo replies
642 */
643static void async_fsinfo(struct smb2_request *c_req)
644{
645	struct async_info *async = c_req->async.private_data;
646	struct ntvfs_request *req = async->req;
647	req->async_states->status = smb2_getinfo_fs_recv(c_req, req, async->parms);
648	talloc_free(async);
649	req->async_states->send_fn(req);
650}
651
652/*
653  return filesystem space info
654*/
655static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs,
656			    struct ntvfs_request *req, union smb_fsinfo *fs)
657{
658	struct cvfs_private *p = ntvfs->private_data;
659	struct smb2_request *c_req;
660	enum smb_fsinfo_level level = fs->generic.level;
661
662	CHECK_ASYNC(req);
663
664	switch (level) {
665		/* some levels go straight through */
666	case RAW_QFS_VOLUME_INFORMATION:
667	case RAW_QFS_SIZE_INFORMATION:
668	case RAW_QFS_DEVICE_INFORMATION:
669	case RAW_QFS_ATTRIBUTE_INFORMATION:
670	case RAW_QFS_QUOTA_INFORMATION:
671	case RAW_QFS_FULL_SIZE_INFORMATION:
672	case RAW_QFS_OBJECTID_INFORMATION:
673		break;
674
675		/* some get mapped */
676	case RAW_QFS_VOLUME_INFO:
677		level = RAW_QFS_VOLUME_INFORMATION;
678		break;
679	case RAW_QFS_SIZE_INFO:
680		level = RAW_QFS_SIZE_INFORMATION;
681		break;
682	case RAW_QFS_DEVICE_INFO:
683		level = RAW_QFS_DEVICE_INFORMATION;
684		break;
685	case RAW_QFS_ATTRIBUTE_INFO:
686		level = RAW_QFS_ATTRIBUTE_INFO;
687		break;
688
689	default:
690		/* the rest get refused for now */
691		DEBUG(0,("fsinfo level %u not possible on SMB2\n",
692			 (unsigned)fs->generic.level));
693		break;
694	}
695
696	fs->generic.level = level;
697	fs->generic.handle = p->roothandle;
698
699	c_req = smb2_getinfo_fs_send(p->tree, fs);
700
701	ASYNC_RECV_TAIL(fs, async_fsinfo);
702}
703
704/*
705  return print queue info
706*/
707static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs,
708			 struct ntvfs_request *req, union smb_lpq *lpq)
709{
710	return NT_STATUS_NOT_SUPPORTED;
711}
712
713/*
714   list files in a directory matching a wildcard pattern
715*/
716static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs,
717				  struct ntvfs_request *req, union smb_search_first *io,
718				  void *search_private,
719				  bool (*callback)(void *, const union smb_search_data *))
720{
721	struct cvfs_private *p = ntvfs->private_data;
722	struct smb2_find f;
723	enum smb_search_data_level smb2_level;
724	uint_t count, i;
725	union smb_search_data *data;
726	NTSTATUS status;
727
728	if (io->generic.level != RAW_SEARCH_TRANS2) {
729		DEBUG(0,("We only support trans2 search in smb2 backend\n"));
730		return NT_STATUS_NOT_SUPPORTED;
731	}
732
733	switch (io->generic.data_level) {
734	case RAW_SEARCH_DATA_DIRECTORY_INFO:
735		smb2_level = SMB2_FIND_DIRECTORY_INFO;
736		break;
737	case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
738		smb2_level = SMB2_FIND_FULL_DIRECTORY_INFO;
739		break;
740	case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
741		smb2_level = SMB2_FIND_BOTH_DIRECTORY_INFO;
742		break;
743	case RAW_SEARCH_DATA_NAME_INFO:
744		smb2_level = SMB2_FIND_NAME_INFO;
745		break;
746	case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
747		smb2_level = SMB2_FIND_ID_FULL_DIRECTORY_INFO;
748		break;
749	case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
750		smb2_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
751		break;
752	default:
753		DEBUG(0,("Unsupported search level %u for smb2 backend\n",
754			 (unsigned)io->generic.data_level));
755		return NT_STATUS_INVALID_INFO_CLASS;
756	}
757
758	/* we do the search on the roothandle. This only works because
759	   search is synchronous, otherwise we'd have no way to
760	   distinguish multiple searches happening at once
761	*/
762	ZERO_STRUCT(f);
763	f.in.file.handle	= p->roothandle;
764	f.in.level              = smb2_level;
765	f.in.pattern		= io->t2ffirst.in.pattern;
766	while (f.in.pattern[0] == '\\') {
767		f.in.pattern++;
768	}
769	f.in.continue_flags	= 0;
770	f.in.max_response_size	= 0x10000;
771
772	status = smb2_find_level(p->tree, req, &f, &count, &data);
773	NT_STATUS_NOT_OK_RETURN(status);
774
775	for (i=0;i<count;i++) {
776		if (!callback(search_private, &data[i])) break;
777	}
778
779	io->t2ffirst.out.handle = 0;
780	io->t2ffirst.out.count = i;
781	/* TODO: fix end_of_file */
782	io->t2ffirst.out.end_of_search = 1;
783
784	talloc_free(data);
785
786	return NT_STATUS_OK;
787}
788
789/* continue a search */
790static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs,
791				 struct ntvfs_request *req, union smb_search_next *io,
792				 void *search_private,
793				 bool (*callback)(void *, const union smb_search_data *))
794{
795	return NT_STATUS_NOT_IMPLEMENTED;
796}
797
798/* close a search */
799static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs,
800				  struct ntvfs_request *req, union smb_search_close *io)
801{
802	return NT_STATUS_NOT_IMPLEMENTED;
803}
804
805/* SMBtrans - not used on file shares */
806static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs,
807			   struct ntvfs_request *req,
808			   struct smb_trans2 *trans2)
809{
810	return NT_STATUS_ACCESS_DENIED;
811}
812
813/* change notify request - always async */
814static NTSTATUS cvfs_notify(struct ntvfs_module_context *ntvfs,
815			    struct ntvfs_request *req,
816			    union smb_notify *io)
817{
818	return NT_STATUS_NOT_IMPLEMENTED;
819}
820
821/*
822  initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
823 */
824NTSTATUS ntvfs_smb2_init(void)
825{
826	NTSTATUS ret;
827	struct ntvfs_ops ops;
828	NTVFS_CURRENT_CRITICAL_SIZES(vers);
829
830	ZERO_STRUCT(ops);
831
832	/* fill in the name and type */
833	ops.name = "smb2";
834	ops.type = NTVFS_DISK;
835
836	/* fill in all the operations */
837	ops.connect = cvfs_connect;
838	ops.disconnect = cvfs_disconnect;
839	ops.unlink = cvfs_unlink;
840	ops.chkpath = cvfs_chkpath;
841	ops.qpathinfo = cvfs_qpathinfo;
842	ops.setpathinfo = cvfs_setpathinfo;
843	ops.open = cvfs_open;
844	ops.mkdir = cvfs_mkdir;
845	ops.rmdir = cvfs_rmdir;
846	ops.rename = cvfs_rename;
847	ops.copy = cvfs_copy;
848	ops.ioctl = cvfs_ioctl;
849	ops.read = cvfs_read;
850	ops.write = cvfs_write;
851	ops.seek = cvfs_seek;
852	ops.flush = cvfs_flush;
853	ops.close = cvfs_close;
854	ops.exit = cvfs_exit;
855	ops.lock = cvfs_lock;
856	ops.setfileinfo = cvfs_setfileinfo;
857	ops.qfileinfo = cvfs_qfileinfo;
858	ops.fsinfo = cvfs_fsinfo;
859	ops.lpq = cvfs_lpq;
860	ops.search_first = cvfs_search_first;
861	ops.search_next = cvfs_search_next;
862	ops.search_close = cvfs_search_close;
863	ops.trans = cvfs_trans;
864	ops.logoff = cvfs_logoff;
865	ops.async_setup = cvfs_async_setup;
866	ops.cancel = cvfs_cancel;
867	ops.notify = cvfs_notify;
868
869	/* register ourselves with the NTVFS subsystem. We register
870	   under the name 'smb2'. */
871	ret = ntvfs_register(&ops, &vers);
872
873	if (!NT_STATUS_IS_OK(ret)) {
874		DEBUG(0,("Failed to register SMB2 backend\n"));
875	}
876
877	return ret;
878}
879