2 Unix SMB/CIFS implementation.
4 CIFS-on-CIFS NTVFS filesystem backend
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) James J Myers 2003 <myersjj@samba.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 this implements a CIFS->CIFS NTVFS filesystem backend.
30 /* this is stored in ntvfs_private */
32 struct smbcli_tree *tree;
33 struct smbcli_transport *transport;
34 struct smbsrv_tcon *tcon;
35 const char *map_calls;
39 /* a structure used to pass information to an async handler */
41 struct smbsrv_request *req;
46 an idle function to cope with messages from the smbd client while
47 waiting for a reply from the server
48 this function won't be needed once all of the cifs backend
49 and the core of smbd is converted to use async calls
51 static void idle_func(struct smbcli_transport *transport, void *p_private)
53 struct cvfs_private *private = p_private;
54 if (socket_pending(private->tcon->smb_conn->connection->socket->fde->fd)) {
55 smbd_process_async(private->tcon->smb_conn);
60 a handler for oplock break events from the server - these need to be passed
63 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
65 struct cvfs_private *private = p_private;
67 DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
68 return req_send_oplock_break(private->tcon, fnum, level);
72 a handler for read events on a connection to a backend server
74 static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags)
76 struct cvfs_private *private = fde->private;
77 struct smbsrv_tcon *tcon = private->tcon;
79 DEBUG(5,("cifs_socket_handler event on fd %d\n", fde->fd));
81 if (!smbcli_transport_process(private->transport)) {
82 /* the connection to our server is dead */
88 connect to a share - used when a tree_connect operation comes in.
90 static NTSTATUS cvfs_connect(struct smbsrv_request *req, const char *sharename)
92 struct smbsrv_tcon *tcon = req->tcon;
94 struct cvfs_private *private;
95 const char *map_calls;
96 const char *host, *user, *pass, *domain, *remote_share;
98 /* Here we need to determine which server to connect to.
99 * For now we use parametric options, type cifs.
100 * Later we will use security=server and auth_server.c.
102 host = lp_parm_string(req->tcon->service, "cifs", "server");
103 user = lp_parm_string(req->tcon->service, "cifs", "user");
104 pass = lp_parm_string(req->tcon->service, "cifs", "password");
105 domain = lp_parm_string(req->tcon->service, "cifs", "domain");
106 remote_share = lp_parm_string(req->tcon->service, "cifs", "share");
108 remote_share = sharename;
111 if (!host || !user || !pass || !domain) {
112 DEBUG(1,("CIFS backend: You must supply server, user, password and domain\n"));
113 return NT_STATUS_INVALID_PARAMETER;
116 private = talloc(req->tcon->mem_ctx, sizeof(struct cvfs_private));
118 return NT_STATUS_NO_MEMORY;
120 ZERO_STRUCTP(private);
122 req->tcon->ntvfs_private = (void *)private;
124 status = smbcli_tree_full_connection(&private->tree,
128 remote_share, "?????",
131 if (!NT_STATUS_IS_OK(status)) {
135 private->transport = private->tree->session->transport;
136 private->tree->session->pid = SVAL(req->in.hdr, HDR_PID);
137 private->tcon = req->tcon;
139 tcon->fs_type = talloc_strdup(tcon->mem_ctx, "NTFS");
140 tcon->dev_type = talloc_strdup(tcon->mem_ctx, "A:");
142 map_calls = lp_parm_string(req->tcon->service, "cifs", "map calls");
144 private->map_calls = talloc_strdup(tcon->mem_ctx, map_calls);
147 /* if we are mapping trans2, then we need to give a trans2
148 pointer in the operations structure */
149 if (private->map_calls && in_list("trans2", private->map_calls, True)) {
150 struct ntvfs_ops *ops = talloc_memdup(tcon->mem_ctx,tcon->ntvfs_ops,sizeof(*ops));
151 static NTSTATUS cvfs_trans2(struct smbsrv_request *,struct smb_trans2 *);
153 return NT_STATUS_NO_MEMORY;
155 ops->trans2 = cvfs_trans2;
156 tcon->ntvfs_ops = ops;
159 /* we need to receive oplock break requests from the server */
160 smbcli_oplock_handler(private->transport, oplock_handler, private);
161 smbcli_transport_idle_handler(private->transport, idle_func, 1, private);
163 private->transport->event.fde->handler = cifs_socket_handler;
164 private->transport->event.fde->private = private;
166 event_context_merge(tcon->smb_conn->connection->event.ctx,
167 private->transport->event.ctx);
169 private->transport->event.ctx = tcon->smb_conn->connection->event.ctx;
175 disconnect from a share
177 static NTSTATUS cvfs_disconnect(struct smbsrv_tcon *tcon)
179 struct cvfs_private *private = tcon->ntvfs_private;
181 smb_tree_disconnect(private->tree);
182 smbcli_tree_close(private->tree);
188 a handler for simple async replies
189 this handler can only be used for functions that don't return any
190 parameters (those that just return a status code)
192 static void async_simple(struct smbcli_request *c_req)
194 struct async_info *async = c_req->async.private;
195 struct smbsrv_request *req = async->req;
196 req->async.status = smbcli_request_simple_recv(c_req);
197 req->async.send_fn(req);
201 /* save some typing for the simple functions */
202 #define ASYNC_RECV_TAIL(io, async_fn) do { \
203 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
205 struct async_info *async; \
206 async = talloc(req->mem_ctx, sizeof(*async)); \
207 if (!async) return NT_STATUS_NO_MEMORY; \
210 c_req->async.private = async; \
212 c_req->async.fn = async_fn; \
213 req->control_flags |= REQ_CONTROL_ASYNC; \
214 return NT_STATUS_OK; \
217 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
220 delete a file - the dirtype specifies the file types to include in the search.
221 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
223 static NTSTATUS cvfs_unlink(struct smbsrv_request *req, struct smb_unlink *unl)
225 struct cvfs_private *private = req->tcon->ntvfs_private;
226 struct smbcli_request *c_req;
228 /* see if the front end will allow us to perform this
229 function asynchronously. */
230 if (!req->async.send_fn) {
231 return smb_raw_unlink(private->tree, unl);
234 c_req = smb_raw_unlink_send(private->tree, unl);
240 a handler for async ioctl replies
242 static void async_ioctl(struct smbcli_request *c_req)
244 struct async_info *async = c_req->async.private;
245 struct smbsrv_request *req = async->req;
246 req->async.status = smb_raw_ioctl_recv(c_req, req->mem_ctx, async->parms);
247 req->async.send_fn(req);
253 static NTSTATUS cvfs_ioctl(struct smbsrv_request *req, union smb_ioctl *io)
255 struct cvfs_private *private = req->tcon->ntvfs_private;
256 struct smbcli_request *c_req;
258 /* see if the front end will allow us to perform this
259 function asynchronously. */
260 if (!req->async.send_fn) {
261 return smb_raw_ioctl(private->tree, req->mem_ctx, io);
264 c_req = smb_raw_ioctl_send(private->tree, io);
266 ASYNC_RECV_TAIL(io, async_ioctl);
270 check if a directory exists
272 static NTSTATUS cvfs_chkpath(struct smbsrv_request *req, struct smb_chkpath *cp)
274 struct cvfs_private *private = req->tcon->ntvfs_private;
275 struct smbcli_request *c_req;
277 if (!req->async.send_fn) {
278 return smb_raw_chkpath(private->tree, cp);
281 c_req = smb_raw_chkpath_send(private->tree, cp);
287 a handler for async qpathinfo replies
289 static void async_qpathinfo(struct smbcli_request *c_req)
291 struct async_info *async = c_req->async.private;
292 struct smbsrv_request *req = async->req;
293 req->async.status = smb_raw_pathinfo_recv(c_req, req->mem_ctx, async->parms);
294 req->async.send_fn(req);
298 return info on a pathname
300 static NTSTATUS cvfs_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info)
302 struct cvfs_private *private = req->tcon->ntvfs_private;
303 struct smbcli_request *c_req;
305 if (!req->async.send_fn) {
306 return smb_raw_pathinfo(private->tree, req->mem_ctx, info);
309 c_req = smb_raw_pathinfo_send(private->tree, info);
311 ASYNC_RECV_TAIL(info, async_qpathinfo);
315 a handler for async qfileinfo replies
317 static void async_qfileinfo(struct smbcli_request *c_req)
319 struct async_info *async = c_req->async.private;
320 struct smbsrv_request *req = async->req;
321 req->async.status = smb_raw_fileinfo_recv(c_req, req->mem_ctx, async->parms);
322 req->async.send_fn(req);
326 query info on a open file
328 static NTSTATUS cvfs_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info)
330 struct cvfs_private *private = req->tcon->ntvfs_private;
331 struct smbcli_request *c_req;
333 if (!req->async.send_fn) {
334 return smb_raw_fileinfo(private->tree, req->mem_ctx, info);
337 c_req = smb_raw_fileinfo_send(private->tree, info);
339 ASYNC_RECV_TAIL(info, async_qfileinfo);
344 set info on a pathname
346 static NTSTATUS cvfs_setpathinfo(struct smbsrv_request *req, union smb_setfileinfo *st)
348 struct cvfs_private *private = req->tcon->ntvfs_private;
349 struct smbcli_request *c_req;
351 if (!req->async.send_fn) {
352 return smb_raw_setpathinfo(private->tree, st);
355 c_req = smb_raw_setpathinfo_send(private->tree, st);
362 a handler for async open replies
364 static void async_open(struct smbcli_request *c_req)
366 struct async_info *async = c_req->async.private;
367 struct smbsrv_request *req = async->req;
368 req->async.status = smb_raw_open_recv(c_req, req->mem_ctx, async->parms);
369 req->async.send_fn(req);
375 static NTSTATUS cvfs_open(struct smbsrv_request *req, union smb_open *io)
377 struct cvfs_private *private = req->tcon->ntvfs_private;
378 struct smbcli_request *c_req;
380 if (private->map_calls && in_list("open", private->map_calls, True) &&
381 io->generic.level != RAW_OPEN_GENERIC) {
382 return ntvfs_map_open(req, io);
385 if (!req->async.send_fn) {
386 return smb_raw_open(private->tree, req->mem_ctx, io);
389 c_req = smb_raw_open_send(private->tree, io);
391 ASYNC_RECV_TAIL(io, async_open);
397 static NTSTATUS cvfs_mkdir(struct smbsrv_request *req, union smb_mkdir *md)
399 struct cvfs_private *private = req->tcon->ntvfs_private;
400 struct smbcli_request *c_req;
402 if (!req->async.send_fn) {
403 return smb_raw_mkdir(private->tree, md);
406 c_req = smb_raw_mkdir_send(private->tree, md);
414 static NTSTATUS cvfs_rmdir(struct smbsrv_request *req, struct smb_rmdir *rd)
416 struct cvfs_private *private = req->tcon->ntvfs_private;
417 struct smbcli_request *c_req;
419 if (!req->async.send_fn) {
420 return smb_raw_rmdir(private->tree, rd);
422 c_req = smb_raw_rmdir_send(private->tree, rd);
428 rename a set of files
430 static NTSTATUS cvfs_rename(struct smbsrv_request *req, union smb_rename *ren)
432 struct cvfs_private *private = req->tcon->ntvfs_private;
433 struct smbcli_request *c_req;
435 if (!req->async.send_fn) {
436 return smb_raw_rename(private->tree, ren);
439 c_req = smb_raw_rename_send(private->tree, ren);
447 static NTSTATUS cvfs_copy(struct smbsrv_request *req, struct smb_copy *cp)
449 return NT_STATUS_NOT_SUPPORTED;
453 a handler for async read replies
455 static void async_read(struct smbcli_request *c_req)
457 struct async_info *async = c_req->async.private;
458 struct smbsrv_request *req = async->req;
459 req->async.status = smb_raw_read_recv(c_req, async->parms);
460 req->async.send_fn(req);
466 static NTSTATUS cvfs_read(struct smbsrv_request *req, union smb_read *rd)
468 struct cvfs_private *private = req->tcon->ntvfs_private;
469 struct smbcli_request *c_req;
471 if (!req->async.send_fn) {
472 return smb_raw_read(private->tree, rd);
475 c_req = smb_raw_read_send(private->tree, rd);
477 ASYNC_RECV_TAIL(rd, async_read);
481 a handler for async write replies
483 static void async_write(struct smbcli_request *c_req)
485 struct async_info *async = c_req->async.private;
486 struct smbsrv_request *req = async->req;
487 req->async.status = smb_raw_write_recv(c_req, async->parms);
488 req->async.send_fn(req);
494 static NTSTATUS cvfs_write(struct smbsrv_request *req, union smb_write *wr)
496 struct cvfs_private *private = req->tcon->ntvfs_private;
497 struct smbcli_request *c_req;
499 if (!req->async.send_fn) {
500 return smb_raw_write(private->tree, wr);
503 c_req = smb_raw_write_send(private->tree, wr);
505 ASYNC_RECV_TAIL(wr, async_write);
511 static NTSTATUS cvfs_seek(struct smbsrv_request *req, struct smb_seek *io)
513 return NT_STATUS_NOT_SUPPORTED;
519 static NTSTATUS cvfs_flush(struct smbsrv_request *req, struct smb_flush *io)
527 static NTSTATUS cvfs_close(struct smbsrv_request *req, union smb_close *io)
529 struct cvfs_private *private = req->tcon->ntvfs_private;
530 struct smbcli_request *c_req;
532 if (!req->async.send_fn) {
533 return smb_raw_close(private->tree, io);
536 c_req = smb_raw_close_send(private->tree, io);
542 exit - closing files?
544 static NTSTATUS cvfs_exit(struct smbsrv_request *req)
546 return NT_STATUS_NOT_SUPPORTED;
552 static NTSTATUS cvfs_lock(struct smbsrv_request *req, union smb_lock *lck)
554 struct cvfs_private *private = req->tcon->ntvfs_private;
555 struct smbcli_request *c_req;
557 if (!req->async.send_fn) {
558 return smb_raw_lock(private->tree, lck);
561 c_req = smb_raw_lock_send(private->tree, lck);
566 set info on a open file
568 static NTSTATUS cvfs_setfileinfo(struct smbsrv_request *req,
569 union smb_setfileinfo *info)
571 struct cvfs_private *private = req->tcon->ntvfs_private;
572 struct smbcli_request *c_req;
574 if (!req->async.send_fn) {
575 return smb_raw_setfileinfo(private->tree, info);
577 c_req = smb_raw_setfileinfo_send(private->tree, info);
584 a handler for async fsinfo replies
586 static void async_fsinfo(struct smbcli_request *c_req)
588 struct async_info *async = c_req->async.private;
589 struct smbsrv_request *req = async->req;
590 req->async.status = smb_raw_fsinfo_recv(c_req, req->mem_ctx, async->parms);
591 req->async.send_fn(req);
595 return filesystem space info
597 static NTSTATUS cvfs_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs)
599 struct cvfs_private *private = req->tcon->ntvfs_private;
600 struct smbcli_request *c_req;
602 if (!req->async.send_fn) {
603 return smb_raw_fsinfo(private->tree, req->mem_ctx, fs);
606 c_req = smb_raw_fsinfo_send(private->tree, req->mem_ctx, fs);
608 ASYNC_RECV_TAIL(fs, async_fsinfo);
612 return print queue info
614 static NTSTATUS cvfs_lpq(struct smbsrv_request *req, union smb_lpq *lpq)
616 return NT_STATUS_NOT_SUPPORTED;
620 list files in a directory matching a wildcard pattern
622 static NTSTATUS cvfs_search_first(struct smbsrv_request *req, union smb_search_first *io,
623 void *search_private,
624 BOOL (*callback)(void *, union smb_search_data *))
626 struct cvfs_private *private = req->tcon->ntvfs_private;
628 return smb_raw_search_first(private->tree, req->mem_ctx, io, search_private, callback);
631 /* continue a search */
632 static NTSTATUS cvfs_search_next(struct smbsrv_request *req, union smb_search_next *io,
633 void *search_private,
634 BOOL (*callback)(void *, union smb_search_data *))
636 struct cvfs_private *private = req->tcon->ntvfs_private;
638 return smb_raw_search_next(private->tree, req->mem_ctx, io, search_private, callback);
642 static NTSTATUS cvfs_search_close(struct smbsrv_request *req, union smb_search_close *io)
644 struct cvfs_private *private = req->tcon->ntvfs_private;
646 return smb_raw_search_close(private->tree, io);
650 a handler for async trans2 replies
652 static void async_trans2(struct smbcli_request *c_req)
654 struct async_info *async = c_req->async.private;
655 struct smbsrv_request *req = async->req;
656 req->async.status = smb_raw_trans2_recv(c_req, req->mem_ctx, async->parms);
657 req->async.send_fn(req);
661 static NTSTATUS cvfs_trans2(struct smbsrv_request *req, struct smb_trans2 *trans2)
663 struct cvfs_private *private = req->tcon->ntvfs_private;
664 struct smbcli_request *c_req;
666 if (!req->async.send_fn) {
667 return smb_raw_trans2(private->tree, req->mem_ctx, trans2);
670 c_req = smb_raw_trans2_send(private->tree, trans2);
672 ASYNC_RECV_TAIL(trans2, async_trans2);
676 /* SMBtrans - not used on file shares */
677 static NTSTATUS cvfs_trans(struct smbsrv_request *req, struct smb_trans2 *trans2)
679 return NT_STATUS_ACCESS_DENIED;
683 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
685 NTSTATUS ntvfs_cifs_init(void)
688 struct ntvfs_ops ops;
692 /* fill in the name and type */
694 ops.type = NTVFS_DISK;
696 /* fill in all the operations */
697 ops.connect = cvfs_connect;
698 ops.disconnect = cvfs_disconnect;
699 ops.unlink = cvfs_unlink;
700 ops.chkpath = cvfs_chkpath;
701 ops.qpathinfo = cvfs_qpathinfo;
702 ops.setpathinfo = cvfs_setpathinfo;
703 ops.open = cvfs_open;
704 ops.mkdir = cvfs_mkdir;
705 ops.rmdir = cvfs_rmdir;
706 ops.rename = cvfs_rename;
707 ops.copy = cvfs_copy;
708 ops.ioctl = cvfs_ioctl;
709 ops.read = cvfs_read;
710 ops.write = cvfs_write;
711 ops.seek = cvfs_seek;
712 ops.flush = cvfs_flush;
713 ops.close = cvfs_close;
714 ops.exit = cvfs_exit;
715 ops.lock = cvfs_lock;
716 ops.setfileinfo = cvfs_setfileinfo;
717 ops.qfileinfo = cvfs_qfileinfo;
718 ops.fsinfo = cvfs_fsinfo;
720 ops.search_first = cvfs_search_first;
721 ops.search_next = cvfs_search_next;
722 ops.search_close = cvfs_search_close;
723 ops.trans = cvfs_trans;
725 /* only define this one for trans2 testing */
728 /* register ourselves with the NTVFS subsystem. We register
729 under the name 'cifs'. */
730 ret = register_backend("ntvfs", &ops);
732 if (!NT_STATUS_IS_OK(ret)) {
733 DEBUG(0,("Failed to register CIFS backend!\n"));