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 #include "libcli/raw/libcliraw.h"
31 #include "smb_server/smb_server.h"
33 /* this is stored in ntvfs_private */
35 struct smbcli_tree *tree;
36 struct smbcli_transport *transport;
37 struct smbsrv_tcon *tcon;
42 /* a structure used to pass information to an async handler */
44 struct smbsrv_request *req;
48 #define SETUP_PID private->tree->session->pid = SVAL(req->in.hdr, HDR_PID)
51 an idle function to cope with messages from the smbd client while
52 waiting for a reply from the server
53 this function won't be needed once all of the cifs backend
54 and the core of smbd is converted to use async calls
56 static void idle_func(struct smbcli_transport *transport, void *p_private)
58 struct cvfs_private *private = p_private;
59 int fd = socket_get_fd(private->tcon->smb_conn->connection->socket);
61 if (socket_pending(fd)) {
62 smbd_process_async(private->tcon->smb_conn);
67 a handler for oplock break events from the server - these need to be passed
70 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
72 struct cvfs_private *private = p_private;
74 DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
75 return req_send_oplock_break(private->tcon, fnum, level);
79 a handler for read events on a connection to a backend server
81 static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde,
82 struct timeval t, uint16_t flags)
84 struct cvfs_private *private = fde->private;
85 struct smbsrv_tcon *tcon = private->tcon;
87 DEBUG(5,("cifs_socket_handler event on fd %d\n", fde->fd));
89 if (!smbcli_transport_process(private->transport)) {
90 /* the connection to our server is dead */
96 connect to a share - used when a tree_connect operation comes in.
98 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
99 struct smbsrv_request *req, const char *sharename)
101 struct smbsrv_tcon *tcon = req->tcon;
103 struct cvfs_private *private;
104 const char *host, *user, *pass, *domain, *remote_share;
106 /* Here we need to determine which server to connect to.
107 * For now we use parametric options, type cifs.
108 * Later we will use security=server and auth_server.c.
110 host = lp_parm_string(req->tcon->service, "cifs", "server");
111 user = lp_parm_string(req->tcon->service, "cifs", "user");
112 pass = lp_parm_string(req->tcon->service, "cifs", "password");
113 domain = lp_parm_string(req->tcon->service, "cifs", "domain");
114 remote_share = lp_parm_string(req->tcon->service, "cifs", "share");
116 remote_share = sharename;
119 if (!host || !user || !pass || !domain) {
120 DEBUG(1,("CIFS backend: You must supply server, user, password and domain\n"));
121 return NT_STATUS_INVALID_PARAMETER;
124 private = talloc_p(req->tcon, struct cvfs_private);
126 return NT_STATUS_NO_MEMORY;
128 ZERO_STRUCTP(private);
130 ntvfs->private_data = private;
132 status = smbcli_tree_full_connection(private,
137 remote_share, "?????",
140 if (!NT_STATUS_IS_OK(status)) {
144 private->transport = private->tree->session->transport;
146 private->tcon = req->tcon;
148 tcon->fs_type = talloc_strdup(tcon, "NTFS");
149 tcon->dev_type = talloc_strdup(tcon, "A:");
151 /* we need to receive oplock break requests from the server */
152 smbcli_oplock_handler(private->transport, oplock_handler, private);
153 smbcli_transport_idle_handler(private->transport, idle_func, 50000, private);
155 private->transport->event.fde->handler = cifs_socket_handler;
156 private->transport->event.fde->private = private;
158 private->transport->event.ctx = event_context_merge(tcon->smb_conn->connection->event.ctx,
159 private->transport->event.ctx);
160 talloc_reference(private, private->transport->event.ctx);
161 private->map_generic = lp_parm_bool(req->tcon->service,
162 "cifs", "mapgeneric", False);
168 disconnect from a share
170 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs,
171 struct smbsrv_tcon *tcon)
173 struct cvfs_private *private = ntvfs->private_data;
175 talloc_free(private);
181 a handler for simple async replies
182 this handler can only be used for functions that don't return any
183 parameters (those that just return a status code)
185 static void async_simple(struct smbcli_request *c_req)
187 struct async_info *async = c_req->async.private;
188 struct smbsrv_request *req = async->req;
189 req->async_states->status = smbcli_request_simple_recv(c_req);
190 req->async_states->send_fn(req);
194 /* save some typing for the simple functions */
195 #define ASYNC_RECV_TAIL(io, async_fn) do { \
196 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
198 struct async_info *async; \
199 async = talloc_p(req, struct async_info); \
200 if (!async) return NT_STATUS_NO_MEMORY; \
203 c_req->async.private = async; \
205 c_req->async.fn = async_fn; \
206 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
207 return NT_STATUS_OK; \
210 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
213 delete a file - the dirtype specifies the file types to include in the search.
214 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
216 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs,
217 struct smbsrv_request *req, struct smb_unlink *unl)
219 struct cvfs_private *private = ntvfs->private_data;
220 struct smbcli_request *c_req;
224 /* see if the front end will allow us to perform this
225 function asynchronously. */
226 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
227 return smb_raw_unlink(private->tree, unl);
230 c_req = smb_raw_unlink_send(private->tree, unl);
236 a handler for async ioctl replies
238 static void async_ioctl(struct smbcli_request *c_req)
240 struct async_info *async = c_req->async.private;
241 struct smbsrv_request *req = async->req;
242 req->async_states->status = smb_raw_ioctl_recv(c_req, req, async->parms);
243 req->async_states->send_fn(req);
249 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs,
250 struct smbsrv_request *req, union smb_ioctl *io)
252 struct cvfs_private *private = ntvfs->private_data;
253 struct smbcli_request *c_req;
257 /* see if the front end will allow us to perform this
258 function asynchronously. */
259 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
260 return smb_raw_ioctl(private->tree, req, io);
263 c_req = smb_raw_ioctl_send(private->tree, io);
265 ASYNC_RECV_TAIL(io, async_ioctl);
269 check if a directory exists
271 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs,
272 struct smbsrv_request *req, struct smb_chkpath *cp)
274 struct cvfs_private *private = ntvfs->private_data;
275 struct smbcli_request *c_req;
279 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
280 return smb_raw_chkpath(private->tree, cp);
283 c_req = smb_raw_chkpath_send(private->tree, cp);
289 a handler for async qpathinfo replies
291 static void async_qpathinfo(struct smbcli_request *c_req)
293 struct async_info *async = c_req->async.private;
294 struct smbsrv_request *req = async->req;
295 req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms);
296 req->async_states->send_fn(req);
300 return info on a pathname
302 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
303 struct smbsrv_request *req, union smb_fileinfo *info)
305 struct cvfs_private *private = ntvfs->private_data;
306 struct smbcli_request *c_req;
310 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
311 return smb_raw_pathinfo(private->tree, req, info);
314 c_req = smb_raw_pathinfo_send(private->tree, info);
316 ASYNC_RECV_TAIL(info, async_qpathinfo);
320 a handler for async qfileinfo replies
322 static void async_qfileinfo(struct smbcli_request *c_req)
324 struct async_info *async = c_req->async.private;
325 struct smbsrv_request *req = async->req;
326 req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms);
327 req->async_states->send_fn(req);
331 query info on a open file
333 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
334 struct smbsrv_request *req, union smb_fileinfo *info)
336 struct cvfs_private *private = ntvfs->private_data;
337 struct smbcli_request *c_req;
341 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
342 return smb_raw_fileinfo(private->tree, req, info);
345 c_req = smb_raw_fileinfo_send(private->tree, info);
347 ASYNC_RECV_TAIL(info, async_qfileinfo);
352 set info on a pathname
354 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
355 struct smbsrv_request *req, union smb_setfileinfo *st)
357 struct cvfs_private *private = ntvfs->private_data;
358 struct smbcli_request *c_req;
362 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
363 return smb_raw_setpathinfo(private->tree, st);
366 c_req = smb_raw_setpathinfo_send(private->tree, st);
373 a handler for async open replies
375 static void async_open(struct smbcli_request *c_req)
377 struct async_info *async = c_req->async.private;
378 struct smbsrv_request *req = async->req;
379 req->async_states->status = smb_raw_open_recv(c_req, req, async->parms);
380 req->async_states->send_fn(req);
386 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs,
387 struct smbsrv_request *req, union smb_open *io)
389 struct cvfs_private *private = ntvfs->private_data;
390 struct smbcli_request *c_req;
394 if (io->generic.level != RAW_OPEN_GENERIC &&
395 private->map_generic) {
396 return ntvfs_map_open(req, io, ntvfs);
399 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
400 return smb_raw_open(private->tree, req, io);
403 c_req = smb_raw_open_send(private->tree, io);
405 ASYNC_RECV_TAIL(io, async_open);
411 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs,
412 struct smbsrv_request *req, union smb_mkdir *md)
414 struct cvfs_private *private = ntvfs->private_data;
415 struct smbcli_request *c_req;
419 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
420 return smb_raw_mkdir(private->tree, md);
423 c_req = smb_raw_mkdir_send(private->tree, md);
431 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs,
432 struct smbsrv_request *req, struct smb_rmdir *rd)
434 struct cvfs_private *private = ntvfs->private_data;
435 struct smbcli_request *c_req;
439 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
440 return smb_raw_rmdir(private->tree, rd);
442 c_req = smb_raw_rmdir_send(private->tree, rd);
448 rename a set of files
450 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs,
451 struct smbsrv_request *req, union smb_rename *ren)
453 struct cvfs_private *private = ntvfs->private_data;
454 struct smbcli_request *c_req;
458 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
459 return smb_raw_rename(private->tree, ren);
462 c_req = smb_raw_rename_send(private->tree, ren);
470 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs,
471 struct smbsrv_request *req, struct smb_copy *cp)
473 return NT_STATUS_NOT_SUPPORTED;
477 a handler for async read replies
479 static void async_read(struct smbcli_request *c_req)
481 struct async_info *async = c_req->async.private;
482 struct smbsrv_request *req = async->req;
483 req->async_states->status = smb_raw_read_recv(c_req, async->parms);
484 req->async_states->send_fn(req);
490 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs,
491 struct smbsrv_request *req, union smb_read *rd)
493 struct cvfs_private *private = ntvfs->private_data;
494 struct smbcli_request *c_req;
498 if (rd->generic.level != RAW_READ_GENERIC &&
499 private->map_generic) {
500 return ntvfs_map_read(req, rd, ntvfs);
503 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
504 return smb_raw_read(private->tree, rd);
507 c_req = smb_raw_read_send(private->tree, rd);
509 ASYNC_RECV_TAIL(rd, async_read);
513 a handler for async write replies
515 static void async_write(struct smbcli_request *c_req)
517 struct async_info *async = c_req->async.private;
518 struct smbsrv_request *req = async->req;
519 req->async_states->status = smb_raw_write_recv(c_req, async->parms);
520 req->async_states->send_fn(req);
526 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs,
527 struct smbsrv_request *req, union smb_write *wr)
529 struct cvfs_private *private = ntvfs->private_data;
530 struct smbcli_request *c_req;
534 if (wr->generic.level != RAW_WRITE_GENERIC &&
535 private->map_generic) {
536 return ntvfs_map_write(req, wr, ntvfs);
539 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
540 return smb_raw_write(private->tree, wr);
543 c_req = smb_raw_write_send(private->tree, wr);
545 ASYNC_RECV_TAIL(wr, async_write);
551 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs,
552 struct smbsrv_request *req, struct smb_seek *io)
554 struct cvfs_private *private = ntvfs->private_data;
555 struct smbcli_request *c_req;
559 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
560 return smb_raw_seek(private->tree, io);
563 c_req = smb_raw_seek_send(private->tree, io);
571 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs,
572 struct smbsrv_request *req, struct smb_flush *io)
574 struct cvfs_private *private = ntvfs->private_data;
575 struct smbcli_request *c_req;
579 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
580 return smb_raw_flush(private->tree, io);
583 c_req = smb_raw_flush_send(private->tree, io);
591 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs,
592 struct smbsrv_request *req, union smb_close *io)
594 struct cvfs_private *private = ntvfs->private_data;
595 struct smbcli_request *c_req;
599 if (io->generic.level != RAW_CLOSE_GENERIC &&
600 private->map_generic) {
601 return ntvfs_map_close(req, io, ntvfs);
604 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
605 return smb_raw_close(private->tree, io);
608 c_req = smb_raw_close_send(private->tree, io);
614 exit - closing files open by the pid
616 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs,
617 struct smbsrv_request *req)
619 struct cvfs_private *private = ntvfs->private_data;
620 struct smbcli_request *c_req;
624 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
625 return smb_raw_exit(private->tree->session);
628 c_req = smb_raw_exit_send(private->tree->session);
634 logoff - closing files open by the user
636 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs,
637 struct smbsrv_request *req)
639 /* we can't do this right in the cifs backend .... */
644 setup for an async call - nothing to do yet
646 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs,
647 struct smbsrv_request *req,
656 static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs,
657 struct smbsrv_request *req)
659 return NT_STATUS_NOT_IMPLEMENTED;
665 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs,
666 struct smbsrv_request *req, union smb_lock *lck)
668 struct cvfs_private *private = ntvfs->private_data;
669 struct smbcli_request *c_req;
673 if (lck->generic.level != RAW_LOCK_GENERIC &&
674 private->map_generic) {
675 return ntvfs_map_lock(req, lck, ntvfs);
678 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
679 return smb_raw_lock(private->tree, lck);
682 c_req = smb_raw_lock_send(private->tree, lck);
687 set info on a open file
689 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
690 struct smbsrv_request *req,
691 union smb_setfileinfo *info)
693 struct cvfs_private *private = ntvfs->private_data;
694 struct smbcli_request *c_req;
698 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
699 return smb_raw_setfileinfo(private->tree, info);
701 c_req = smb_raw_setfileinfo_send(private->tree, info);
708 a handler for async fsinfo replies
710 static void async_fsinfo(struct smbcli_request *c_req)
712 struct async_info *async = c_req->async.private;
713 struct smbsrv_request *req = async->req;
714 req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms);
715 req->async_states->send_fn(req);
719 return filesystem space info
721 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs,
722 struct smbsrv_request *req, union smb_fsinfo *fs)
724 struct cvfs_private *private = ntvfs->private_data;
725 struct smbcli_request *c_req;
729 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
730 return smb_raw_fsinfo(private->tree, req, fs);
733 c_req = smb_raw_fsinfo_send(private->tree, req, fs);
735 ASYNC_RECV_TAIL(fs, async_fsinfo);
739 return print queue info
741 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs,
742 struct smbsrv_request *req, union smb_lpq *lpq)
744 return NT_STATUS_NOT_SUPPORTED;
748 list files in a directory matching a wildcard pattern
750 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs,
751 struct smbsrv_request *req, union smb_search_first *io,
752 void *search_private,
753 BOOL (*callback)(void *, union smb_search_data *))
755 struct cvfs_private *private = ntvfs->private_data;
759 return smb_raw_search_first(private->tree, req, io, search_private, callback);
762 /* continue a search */
763 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs,
764 struct smbsrv_request *req, union smb_search_next *io,
765 void *search_private,
766 BOOL (*callback)(void *, union smb_search_data *))
768 struct cvfs_private *private = ntvfs->private_data;
772 return smb_raw_search_next(private->tree, req, io, search_private, callback);
776 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs,
777 struct smbsrv_request *req, union smb_search_close *io)
779 struct cvfs_private *private = ntvfs->private_data;
783 return smb_raw_search_close(private->tree, io);
787 a handler for async trans2 replies
789 static void async_trans2(struct smbcli_request *c_req)
791 struct async_info *async = c_req->async.private;
792 struct smbsrv_request *req = async->req;
793 req->async_states->status = smb_raw_trans2_recv(c_req, req, async->parms);
794 req->async_states->send_fn(req);
798 static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs,
799 struct smbsrv_request *req, struct smb_trans2 *trans2)
801 struct cvfs_private *private = ntvfs->private_data;
802 struct smbcli_request *c_req;
806 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
807 return smb_raw_trans2(private->tree, req, trans2);
810 c_req = smb_raw_trans2_send(private->tree, trans2);
812 ASYNC_RECV_TAIL(trans2, async_trans2);
816 /* SMBtrans - not used on file shares */
817 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs,
818 struct smbsrv_request *req, struct smb_trans2 *trans2)
820 return NT_STATUS_ACCESS_DENIED;
824 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
826 NTSTATUS ntvfs_cifs_init(void)
829 struct ntvfs_ops ops;
833 /* fill in the name and type */
835 ops.type = NTVFS_DISK;
837 /* fill in all the operations */
838 ops.connect = cvfs_connect;
839 ops.disconnect = cvfs_disconnect;
840 ops.unlink = cvfs_unlink;
841 ops.chkpath = cvfs_chkpath;
842 ops.qpathinfo = cvfs_qpathinfo;
843 ops.setpathinfo = cvfs_setpathinfo;
844 ops.openfile = cvfs_open;
845 ops.mkdir = cvfs_mkdir;
846 ops.rmdir = cvfs_rmdir;
847 ops.rename = cvfs_rename;
848 ops.copy = cvfs_copy;
849 ops.ioctl = cvfs_ioctl;
850 ops.read = cvfs_read;
851 ops.write = cvfs_write;
852 ops.seek = cvfs_seek;
853 ops.flush = cvfs_flush;
854 ops.close = cvfs_close;
855 ops.exit = cvfs_exit;
856 ops.lock = cvfs_lock;
857 ops.setfileinfo = cvfs_setfileinfo;
858 ops.qfileinfo = cvfs_qfileinfo;
859 ops.fsinfo = cvfs_fsinfo;
861 ops.search_first = cvfs_search_first;
862 ops.search_next = cvfs_search_next;
863 ops.search_close = cvfs_search_close;
864 ops.trans = cvfs_trans;
865 ops.logoff = cvfs_logoff;
866 ops.async_setup = cvfs_async_setup;
867 ops.cancel = cvfs_cancel;
869 if (lp_parm_bool(-1, "cifs", "maptrans2", False)) {
870 ops.trans2 = cvfs_trans2;
873 /* register ourselves with the NTVFS subsystem. We register
874 under the name 'cifs'. */
875 ret = ntvfs_register(&ops);
877 if (!NT_STATUS_IS_OK(ret)) {
878 DEBUG(0,("Failed to register CIFS backend!\n"));