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;
39 /* a structure used to pass information to an async handler */
41 struct smbsrv_request *req;
45 #define SETUP_PID private->tree->session->pid = SVAL(req->in.hdr, HDR_PID)
48 an idle function to cope with messages from the smbd client while
49 waiting for a reply from the server
50 this function won't be needed once all of the cifs backend
51 and the core of smbd is converted to use async calls
53 static void idle_func(struct smbcli_transport *transport, void *p_private)
55 struct cvfs_private *private = p_private;
56 int fd = socket_get_fd(private->tcon->smb_conn->connection->socket);
58 if (socket_pending(fd)) {
59 smbd_process_async(private->tcon->smb_conn);
64 a handler for oplock break events from the server - these need to be passed
67 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
69 struct cvfs_private *private = p_private;
71 DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
72 return req_send_oplock_break(private->tcon, fnum, level);
76 a handler for read events on a connection to a backend server
78 static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags)
80 struct cvfs_private *private = fde->private;
81 struct smbsrv_tcon *tcon = private->tcon;
83 DEBUG(5,("cifs_socket_handler event on fd %d\n", fde->fd));
85 if (!smbcli_transport_process(private->transport)) {
86 /* the connection to our server is dead */
92 connect to a share - used when a tree_connect operation comes in.
94 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
95 struct smbsrv_request *req, const char *sharename)
97 struct smbsrv_tcon *tcon = req->tcon;
99 struct cvfs_private *private;
100 const char *host, *user, *pass, *domain, *remote_share;
102 /* Here we need to determine which server to connect to.
103 * For now we use parametric options, type cifs.
104 * Later we will use security=server and auth_server.c.
106 host = lp_parm_string(req->tcon->service, "cifs", "server");
107 user = lp_parm_string(req->tcon->service, "cifs", "user");
108 pass = lp_parm_string(req->tcon->service, "cifs", "password");
109 domain = lp_parm_string(req->tcon->service, "cifs", "domain");
110 remote_share = lp_parm_string(req->tcon->service, "cifs", "share");
112 remote_share = sharename;
115 if (!host || !user || !pass || !domain) {
116 DEBUG(1,("CIFS backend: You must supply server, user, password and domain\n"));
117 return NT_STATUS_INVALID_PARAMETER;
120 private = talloc(req->tcon, sizeof(struct cvfs_private));
122 return NT_STATUS_NO_MEMORY;
124 ZERO_STRUCTP(private);
126 ntvfs->private_data = private;
128 status = smbcli_tree_full_connection(private,
133 remote_share, "?????",
136 if (!NT_STATUS_IS_OK(status)) {
140 private->transport = private->tree->session->transport;
142 private->tcon = req->tcon;
144 tcon->fs_type = talloc_strdup(tcon, "NTFS");
145 tcon->dev_type = talloc_strdup(tcon, "A:");
147 /* we need to receive oplock break requests from the server */
148 smbcli_oplock_handler(private->transport, oplock_handler, private);
149 smbcli_transport_idle_handler(private->transport, idle_func, 1, private);
151 private->transport->event.fde->handler = cifs_socket_handler;
152 private->transport->event.fde->private = private;
154 private->transport->event.ctx = event_context_merge(tcon->smb_conn->connection->event.ctx,
155 private->transport->event.ctx);
156 talloc_reference(private, private->transport->event.ctx);
157 private->map_generic = lp_parm_bool(req->tcon->service,
158 "cifs", "mapgeneric", False);
164 disconnect from a share
166 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs,
167 struct smbsrv_tcon *tcon)
169 struct cvfs_private *private = ntvfs->private_data;
171 talloc_free(private);
177 a handler for simple async replies
178 this handler can only be used for functions that don't return any
179 parameters (those that just return a status code)
181 static void async_simple(struct smbcli_request *c_req)
183 struct async_info *async = c_req->async.private;
184 struct smbsrv_request *req = async->req;
185 req->async_states->status = smbcli_request_simple_recv(c_req);
186 req->async_states->send_fn(req);
190 /* save some typing for the simple functions */
191 #define ASYNC_RECV_TAIL(io, async_fn) do { \
192 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
194 struct async_info *async; \
195 async = talloc_p(req, struct async_info); \
196 if (!async) return NT_STATUS_NO_MEMORY; \
199 c_req->async.private = async; \
201 c_req->async.fn = async_fn; \
202 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
203 return NT_STATUS_OK; \
206 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
209 delete a file - the dirtype specifies the file types to include in the search.
210 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
212 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs,
213 struct smbsrv_request *req, struct smb_unlink *unl)
215 struct cvfs_private *private = ntvfs->private_data;
216 struct smbcli_request *c_req;
220 /* see if the front end will allow us to perform this
221 function asynchronously. */
222 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
223 return smb_raw_unlink(private->tree, unl);
226 c_req = smb_raw_unlink_send(private->tree, unl);
232 a handler for async ioctl replies
234 static void async_ioctl(struct smbcli_request *c_req)
236 struct async_info *async = c_req->async.private;
237 struct smbsrv_request *req = async->req;
238 req->async_states->status = smb_raw_ioctl_recv(c_req, req, async->parms);
239 req->async_states->send_fn(req);
245 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs,
246 struct smbsrv_request *req, union smb_ioctl *io)
248 struct cvfs_private *private = ntvfs->private_data;
249 struct smbcli_request *c_req;
253 /* see if the front end will allow us to perform this
254 function asynchronously. */
255 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
256 return smb_raw_ioctl(private->tree, req, io);
259 c_req = smb_raw_ioctl_send(private->tree, io);
261 ASYNC_RECV_TAIL(io, async_ioctl);
265 check if a directory exists
267 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs,
268 struct smbsrv_request *req, struct smb_chkpath *cp)
270 struct cvfs_private *private = ntvfs->private_data;
271 struct smbcli_request *c_req;
275 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
276 return smb_raw_chkpath(private->tree, cp);
279 c_req = smb_raw_chkpath_send(private->tree, cp);
285 a handler for async qpathinfo replies
287 static void async_qpathinfo(struct smbcli_request *c_req)
289 struct async_info *async = c_req->async.private;
290 struct smbsrv_request *req = async->req;
291 req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms);
292 req->async_states->send_fn(req);
296 return info on a pathname
298 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
299 struct smbsrv_request *req, union smb_fileinfo *info)
301 struct cvfs_private *private = ntvfs->private_data;
302 struct smbcli_request *c_req;
306 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
307 return smb_raw_pathinfo(private->tree, req, info);
310 c_req = smb_raw_pathinfo_send(private->tree, info);
312 ASYNC_RECV_TAIL(info, async_qpathinfo);
316 a handler for async qfileinfo replies
318 static void async_qfileinfo(struct smbcli_request *c_req)
320 struct async_info *async = c_req->async.private;
321 struct smbsrv_request *req = async->req;
322 req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms);
323 req->async_states->send_fn(req);
327 query info on a open file
329 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
330 struct smbsrv_request *req, union smb_fileinfo *info)
332 struct cvfs_private *private = ntvfs->private_data;
333 struct smbcli_request *c_req;
337 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
338 return smb_raw_fileinfo(private->tree, req, info);
341 c_req = smb_raw_fileinfo_send(private->tree, info);
343 ASYNC_RECV_TAIL(info, async_qfileinfo);
348 set info on a pathname
350 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
351 struct smbsrv_request *req, union smb_setfileinfo *st)
353 struct cvfs_private *private = ntvfs->private_data;
354 struct smbcli_request *c_req;
358 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
359 return smb_raw_setpathinfo(private->tree, st);
362 c_req = smb_raw_setpathinfo_send(private->tree, st);
369 a handler for async open replies
371 static void async_open(struct smbcli_request *c_req)
373 struct async_info *async = c_req->async.private;
374 struct smbsrv_request *req = async->req;
375 req->async_states->status = smb_raw_open_recv(c_req, req, async->parms);
376 req->async_states->send_fn(req);
382 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs,
383 struct smbsrv_request *req, union smb_open *io)
385 struct cvfs_private *private = ntvfs->private_data;
386 struct smbcli_request *c_req;
390 if (io->generic.level != RAW_OPEN_GENERIC &&
391 private->map_generic) {
392 return ntvfs_map_open(req, io, ntvfs);
395 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
396 return smb_raw_open(private->tree, req, io);
399 c_req = smb_raw_open_send(private->tree, io);
401 ASYNC_RECV_TAIL(io, async_open);
407 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs,
408 struct smbsrv_request *req, union smb_mkdir *md)
410 struct cvfs_private *private = ntvfs->private_data;
411 struct smbcli_request *c_req;
415 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
416 return smb_raw_mkdir(private->tree, md);
419 c_req = smb_raw_mkdir_send(private->tree, md);
427 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs,
428 struct smbsrv_request *req, struct smb_rmdir *rd)
430 struct cvfs_private *private = ntvfs->private_data;
431 struct smbcli_request *c_req;
435 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
436 return smb_raw_rmdir(private->tree, rd);
438 c_req = smb_raw_rmdir_send(private->tree, rd);
444 rename a set of files
446 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs,
447 struct smbsrv_request *req, union smb_rename *ren)
449 struct cvfs_private *private = ntvfs->private_data;
450 struct smbcli_request *c_req;
454 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
455 return smb_raw_rename(private->tree, ren);
458 c_req = smb_raw_rename_send(private->tree, ren);
466 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs,
467 struct smbsrv_request *req, struct smb_copy *cp)
469 return NT_STATUS_NOT_SUPPORTED;
473 a handler for async read replies
475 static void async_read(struct smbcli_request *c_req)
477 struct async_info *async = c_req->async.private;
478 struct smbsrv_request *req = async->req;
479 req->async_states->status = smb_raw_read_recv(c_req, async->parms);
480 req->async_states->send_fn(req);
486 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs,
487 struct smbsrv_request *req, union smb_read *rd)
489 struct cvfs_private *private = ntvfs->private_data;
490 struct smbcli_request *c_req;
494 if (rd->generic.level != RAW_READ_GENERIC &&
495 private->map_generic) {
496 return ntvfs_map_read(req, rd, ntvfs);
499 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
500 return smb_raw_read(private->tree, rd);
503 c_req = smb_raw_read_send(private->tree, rd);
505 ASYNC_RECV_TAIL(rd, async_read);
509 a handler for async write replies
511 static void async_write(struct smbcli_request *c_req)
513 struct async_info *async = c_req->async.private;
514 struct smbsrv_request *req = async->req;
515 req->async_states->status = smb_raw_write_recv(c_req, async->parms);
516 req->async_states->send_fn(req);
522 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs,
523 struct smbsrv_request *req, union smb_write *wr)
525 struct cvfs_private *private = ntvfs->private_data;
526 struct smbcli_request *c_req;
530 if (wr->generic.level != RAW_WRITE_GENERIC &&
531 private->map_generic) {
532 return ntvfs_map_write(req, wr, ntvfs);
535 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
536 return smb_raw_write(private->tree, wr);
539 c_req = smb_raw_write_send(private->tree, wr);
541 ASYNC_RECV_TAIL(wr, async_write);
547 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs,
548 struct smbsrv_request *req, struct smb_seek *io)
550 struct cvfs_private *private = ntvfs->private_data;
551 struct smbcli_request *c_req;
555 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
556 return smb_raw_seek(private->tree, io);
559 c_req = smb_raw_seek_send(private->tree, io);
567 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs,
568 struct smbsrv_request *req, struct smb_flush *io)
570 struct cvfs_private *private = ntvfs->private_data;
571 struct smbcli_request *c_req;
575 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
576 return smb_raw_flush(private->tree, io);
579 c_req = smb_raw_flush_send(private->tree, io);
587 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs,
588 struct smbsrv_request *req, union smb_close *io)
590 struct cvfs_private *private = ntvfs->private_data;
591 struct smbcli_request *c_req;
595 if (io->generic.level != RAW_CLOSE_GENERIC &&
596 private->map_generic) {
597 return ntvfs_map_close(req, io, ntvfs);
600 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
601 return smb_raw_close(private->tree, io);
604 c_req = smb_raw_close_send(private->tree, io);
610 exit - closing files open by the pid
612 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs,
613 struct smbsrv_request *req)
615 struct cvfs_private *private = ntvfs->private_data;
616 struct smbcli_request *c_req;
620 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
621 return smb_raw_exit(private->tree->session);
624 c_req = smb_raw_exit_send(private->tree->session);
630 logoff - closing files open by the user
632 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs,
633 struct smbsrv_request *req)
635 /* we can't do this right in the cifs backend .... */
640 setup for an async call - nothing to do yet
642 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs,
643 struct smbsrv_request *req,
652 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs,
653 struct smbsrv_request *req, union smb_lock *lck)
655 struct cvfs_private *private = ntvfs->private_data;
656 struct smbcli_request *c_req;
660 if (lck->generic.level != RAW_LOCK_GENERIC &&
661 private->map_generic) {
662 return ntvfs_map_lock(req, lck, ntvfs);
665 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
666 return smb_raw_lock(private->tree, lck);
669 c_req = smb_raw_lock_send(private->tree, lck);
674 set info on a open file
676 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
677 struct smbsrv_request *req,
678 union smb_setfileinfo *info)
680 struct cvfs_private *private = ntvfs->private_data;
681 struct smbcli_request *c_req;
685 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
686 return smb_raw_setfileinfo(private->tree, info);
688 c_req = smb_raw_setfileinfo_send(private->tree, info);
695 a handler for async fsinfo replies
697 static void async_fsinfo(struct smbcli_request *c_req)
699 struct async_info *async = c_req->async.private;
700 struct smbsrv_request *req = async->req;
701 req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms);
702 req->async_states->send_fn(req);
706 return filesystem space info
708 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs,
709 struct smbsrv_request *req, union smb_fsinfo *fs)
711 struct cvfs_private *private = ntvfs->private_data;
712 struct smbcli_request *c_req;
716 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
717 return smb_raw_fsinfo(private->tree, req, fs);
720 c_req = smb_raw_fsinfo_send(private->tree, req, fs);
722 ASYNC_RECV_TAIL(fs, async_fsinfo);
726 return print queue info
728 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs,
729 struct smbsrv_request *req, union smb_lpq *lpq)
731 return NT_STATUS_NOT_SUPPORTED;
735 list files in a directory matching a wildcard pattern
737 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs,
738 struct smbsrv_request *req, union smb_search_first *io,
739 void *search_private,
740 BOOL (*callback)(void *, union smb_search_data *))
742 struct cvfs_private *private = ntvfs->private_data;
746 return smb_raw_search_first(private->tree, req, io, search_private, callback);
749 /* continue a search */
750 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs,
751 struct smbsrv_request *req, union smb_search_next *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_next(private->tree, req, io, search_private, callback);
763 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs,
764 struct smbsrv_request *req, union smb_search_close *io)
766 struct cvfs_private *private = ntvfs->private_data;
770 return smb_raw_search_close(private->tree, io);
774 a handler for async trans2 replies
776 static void async_trans2(struct smbcli_request *c_req)
778 struct async_info *async = c_req->async.private;
779 struct smbsrv_request *req = async->req;
780 req->async_states->status = smb_raw_trans2_recv(c_req, req, async->parms);
781 req->async_states->send_fn(req);
785 static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs,
786 struct smbsrv_request *req, struct smb_trans2 *trans2)
788 struct cvfs_private *private = ntvfs->private_data;
789 struct smbcli_request *c_req;
793 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
794 return smb_raw_trans2(private->tree, req, trans2);
797 c_req = smb_raw_trans2_send(private->tree, trans2);
799 ASYNC_RECV_TAIL(trans2, async_trans2);
803 /* SMBtrans - not used on file shares */
804 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs,
805 struct smbsrv_request *req, struct smb_trans2 *trans2)
807 return NT_STATUS_ACCESS_DENIED;
811 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
813 NTSTATUS ntvfs_cifs_init(void)
816 struct ntvfs_ops ops;
820 /* fill in the name and type */
822 ops.type = NTVFS_DISK;
824 /* fill in all the operations */
825 ops.connect = cvfs_connect;
826 ops.disconnect = cvfs_disconnect;
827 ops.unlink = cvfs_unlink;
828 ops.chkpath = cvfs_chkpath;
829 ops.qpathinfo = cvfs_qpathinfo;
830 ops.setpathinfo = cvfs_setpathinfo;
831 ops.open = cvfs_open;
832 ops.mkdir = cvfs_mkdir;
833 ops.rmdir = cvfs_rmdir;
834 ops.rename = cvfs_rename;
835 ops.copy = cvfs_copy;
836 ops.ioctl = cvfs_ioctl;
837 ops.read = cvfs_read;
838 ops.write = cvfs_write;
839 ops.seek = cvfs_seek;
840 ops.flush = cvfs_flush;
841 ops.close = cvfs_close;
842 ops.exit = cvfs_exit;
843 ops.lock = cvfs_lock;
844 ops.setfileinfo = cvfs_setfileinfo;
845 ops.qfileinfo = cvfs_qfileinfo;
846 ops.fsinfo = cvfs_fsinfo;
848 ops.search_first = cvfs_search_first;
849 ops.search_next = cvfs_search_next;
850 ops.search_close = cvfs_search_close;
851 ops.trans = cvfs_trans;
852 ops.logoff = cvfs_logoff;
853 ops.async_setup = cvfs_async_setup;
855 if (lp_parm_bool(-1, "cifs", "maptrans2", False)) {
856 ops.trans2 = cvfs_trans2;
859 /* register ourselves with the NTVFS subsystem. We register
860 under the name 'cifs'. */
861 ret = register_backend("ntvfs", &ops);
863 if (!NT_STATUS_IS_OK(ret)) {
864 DEBUG(0,("Failed to register CIFS backend!\n"));