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.
29 #include "libcli/raw/libcliraw.h"
30 #include "smb_server/smb_server.h"
32 /* this is stored in ntvfs_private */
34 struct smbcli_tree *tree;
35 struct smbcli_transport *transport;
36 struct smbsrv_tcon *tcon;
41 /* a structure used to pass information to an async handler */
43 struct smbsrv_request *req;
47 #define SETUP_PID private->tree->session->pid = SVAL(req->in.hdr, HDR_PID)
50 an idle function to cope with messages from the smbd client while
51 waiting for a reply from the server
52 this function won't be needed once all of the cifs backend
53 and the core of smbd is converted to use async calls
55 static void idle_func(struct smbcli_transport *transport, void *p_private)
57 struct cvfs_private *private = p_private;
58 int fd = socket_get_fd(private->tcon->smb_conn->connection->socket);
60 if (socket_pending(fd)) {
61 smbd_process_async(private->tcon->smb_conn);
66 a handler for oplock break events from the server - these need to be passed
69 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
71 struct cvfs_private *private = p_private;
73 DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
74 return req_send_oplock_break(private->tcon, fnum, level);
78 a handler for read events on a connection to a backend server
80 static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags)
82 struct cvfs_private *private = fde->private;
83 struct smbsrv_tcon *tcon = private->tcon;
85 DEBUG(5,("cifs_socket_handler event on fd %d\n", fde->fd));
87 if (!smbcli_transport_process(private->transport)) {
88 /* the connection to our server is dead */
94 connect to a share - used when a tree_connect operation comes in.
96 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
97 struct smbsrv_request *req, const char *sharename)
99 struct smbsrv_tcon *tcon = req->tcon;
101 struct cvfs_private *private;
102 const char *host, *user, *pass, *domain, *remote_share;
104 /* Here we need to determine which server to connect to.
105 * For now we use parametric options, type cifs.
106 * Later we will use security=server and auth_server.c.
108 host = lp_parm_string(req->tcon->service, "cifs", "server");
109 user = lp_parm_string(req->tcon->service, "cifs", "user");
110 pass = lp_parm_string(req->tcon->service, "cifs", "password");
111 domain = lp_parm_string(req->tcon->service, "cifs", "domain");
112 remote_share = lp_parm_string(req->tcon->service, "cifs", "share");
114 remote_share = sharename;
117 if (!host || !user || !pass || !domain) {
118 DEBUG(1,("CIFS backend: You must supply server, user, password and domain\n"));
119 return NT_STATUS_INVALID_PARAMETER;
122 private = talloc(req->tcon, sizeof(struct cvfs_private));
124 return NT_STATUS_NO_MEMORY;
126 ZERO_STRUCTP(private);
128 ntvfs->private_data = private;
130 status = smbcli_tree_full_connection(private,
135 remote_share, "?????",
138 if (!NT_STATUS_IS_OK(status)) {
142 private->transport = private->tree->session->transport;
144 private->tcon = req->tcon;
146 tcon->fs_type = talloc_strdup(tcon, "NTFS");
147 tcon->dev_type = talloc_strdup(tcon, "A:");
149 /* we need to receive oplock break requests from the server */
150 smbcli_oplock_handler(private->transport, oplock_handler, private);
151 smbcli_transport_idle_handler(private->transport, idle_func, 1, private);
153 private->transport->event.fde->handler = cifs_socket_handler;
154 private->transport->event.fde->private = private;
156 private->transport->event.ctx = event_context_merge(tcon->smb_conn->connection->event.ctx,
157 private->transport->event.ctx);
158 talloc_reference(private, private->transport->event.ctx);
159 private->map_generic = lp_parm_bool(req->tcon->service,
160 "cifs", "mapgeneric", False);
166 disconnect from a share
168 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs,
169 struct smbsrv_tcon *tcon)
171 struct cvfs_private *private = ntvfs->private_data;
173 talloc_free(private);
179 a handler for simple async replies
180 this handler can only be used for functions that don't return any
181 parameters (those that just return a status code)
183 static void async_simple(struct smbcli_request *c_req)
185 struct async_info *async = c_req->async.private;
186 struct smbsrv_request *req = async->req;
187 req->async_states->status = smbcli_request_simple_recv(c_req);
188 req->async_states->send_fn(req);
192 /* save some typing for the simple functions */
193 #define ASYNC_RECV_TAIL(io, async_fn) do { \
194 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
196 struct async_info *async; \
197 async = talloc_p(req, struct async_info); \
198 if (!async) return NT_STATUS_NO_MEMORY; \
201 c_req->async.private = async; \
203 c_req->async.fn = async_fn; \
204 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
205 return NT_STATUS_OK; \
208 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
211 delete a file - the dirtype specifies the file types to include in the search.
212 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
214 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs,
215 struct smbsrv_request *req, struct smb_unlink *unl)
217 struct cvfs_private *private = ntvfs->private_data;
218 struct smbcli_request *c_req;
222 /* see if the front end will allow us to perform this
223 function asynchronously. */
224 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
225 return smb_raw_unlink(private->tree, unl);
228 c_req = smb_raw_unlink_send(private->tree, unl);
234 a handler for async ioctl replies
236 static void async_ioctl(struct smbcli_request *c_req)
238 struct async_info *async = c_req->async.private;
239 struct smbsrv_request *req = async->req;
240 req->async_states->status = smb_raw_ioctl_recv(c_req, req, async->parms);
241 req->async_states->send_fn(req);
247 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs,
248 struct smbsrv_request *req, union smb_ioctl *io)
250 struct cvfs_private *private = ntvfs->private_data;
251 struct smbcli_request *c_req;
255 /* see if the front end will allow us to perform this
256 function asynchronously. */
257 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
258 return smb_raw_ioctl(private->tree, req, io);
261 c_req = smb_raw_ioctl_send(private->tree, io);
263 ASYNC_RECV_TAIL(io, async_ioctl);
267 check if a directory exists
269 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs,
270 struct smbsrv_request *req, struct smb_chkpath *cp)
272 struct cvfs_private *private = ntvfs->private_data;
273 struct smbcli_request *c_req;
277 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
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_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms);
294 req->async_states->send_fn(req);
298 return info on a pathname
300 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
301 struct smbsrv_request *req, union smb_fileinfo *info)
303 struct cvfs_private *private = ntvfs->private_data;
304 struct smbcli_request *c_req;
308 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
309 return smb_raw_pathinfo(private->tree, req, info);
312 c_req = smb_raw_pathinfo_send(private->tree, info);
314 ASYNC_RECV_TAIL(info, async_qpathinfo);
318 a handler for async qfileinfo replies
320 static void async_qfileinfo(struct smbcli_request *c_req)
322 struct async_info *async = c_req->async.private;
323 struct smbsrv_request *req = async->req;
324 req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms);
325 req->async_states->send_fn(req);
329 query info on a open file
331 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
332 struct smbsrv_request *req, union smb_fileinfo *info)
334 struct cvfs_private *private = ntvfs->private_data;
335 struct smbcli_request *c_req;
339 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
340 return smb_raw_fileinfo(private->tree, req, info);
343 c_req = smb_raw_fileinfo_send(private->tree, info);
345 ASYNC_RECV_TAIL(info, async_qfileinfo);
350 set info on a pathname
352 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
353 struct smbsrv_request *req, union smb_setfileinfo *st)
355 struct cvfs_private *private = ntvfs->private_data;
356 struct smbcli_request *c_req;
360 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
361 return smb_raw_setpathinfo(private->tree, st);
364 c_req = smb_raw_setpathinfo_send(private->tree, st);
371 a handler for async open replies
373 static void async_open(struct smbcli_request *c_req)
375 struct async_info *async = c_req->async.private;
376 struct smbsrv_request *req = async->req;
377 req->async_states->status = smb_raw_open_recv(c_req, req, async->parms);
378 req->async_states->send_fn(req);
384 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs,
385 struct smbsrv_request *req, union smb_open *io)
387 struct cvfs_private *private = ntvfs->private_data;
388 struct smbcli_request *c_req;
392 if (io->generic.level != RAW_OPEN_GENERIC &&
393 private->map_generic) {
394 return ntvfs_map_open(req, io, ntvfs);
397 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
398 return smb_raw_open(private->tree, req, io);
401 c_req = smb_raw_open_send(private->tree, io);
403 ASYNC_RECV_TAIL(io, async_open);
409 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs,
410 struct smbsrv_request *req, union smb_mkdir *md)
412 struct cvfs_private *private = ntvfs->private_data;
413 struct smbcli_request *c_req;
417 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
418 return smb_raw_mkdir(private->tree, md);
421 c_req = smb_raw_mkdir_send(private->tree, md);
429 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs,
430 struct smbsrv_request *req, struct smb_rmdir *rd)
432 struct cvfs_private *private = ntvfs->private_data;
433 struct smbcli_request *c_req;
437 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
438 return smb_raw_rmdir(private->tree, rd);
440 c_req = smb_raw_rmdir_send(private->tree, rd);
446 rename a set of files
448 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs,
449 struct smbsrv_request *req, union smb_rename *ren)
451 struct cvfs_private *private = ntvfs->private_data;
452 struct smbcli_request *c_req;
456 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
457 return smb_raw_rename(private->tree, ren);
460 c_req = smb_raw_rename_send(private->tree, ren);
468 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs,
469 struct smbsrv_request *req, struct smb_copy *cp)
471 return NT_STATUS_NOT_SUPPORTED;
475 a handler for async read replies
477 static void async_read(struct smbcli_request *c_req)
479 struct async_info *async = c_req->async.private;
480 struct smbsrv_request *req = async->req;
481 req->async_states->status = smb_raw_read_recv(c_req, async->parms);
482 req->async_states->send_fn(req);
488 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs,
489 struct smbsrv_request *req, union smb_read *rd)
491 struct cvfs_private *private = ntvfs->private_data;
492 struct smbcli_request *c_req;
496 if (rd->generic.level != RAW_READ_GENERIC &&
497 private->map_generic) {
498 return ntvfs_map_read(req, rd, ntvfs);
501 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
502 return smb_raw_read(private->tree, rd);
505 c_req = smb_raw_read_send(private->tree, rd);
507 ASYNC_RECV_TAIL(rd, async_read);
511 a handler for async write replies
513 static void async_write(struct smbcli_request *c_req)
515 struct async_info *async = c_req->async.private;
516 struct smbsrv_request *req = async->req;
517 req->async_states->status = smb_raw_write_recv(c_req, async->parms);
518 req->async_states->send_fn(req);
524 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs,
525 struct smbsrv_request *req, union smb_write *wr)
527 struct cvfs_private *private = ntvfs->private_data;
528 struct smbcli_request *c_req;
532 if (wr->generic.level != RAW_WRITE_GENERIC &&
533 private->map_generic) {
534 return ntvfs_map_write(req, wr, ntvfs);
537 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
538 return smb_raw_write(private->tree, wr);
541 c_req = smb_raw_write_send(private->tree, wr);
543 ASYNC_RECV_TAIL(wr, async_write);
549 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs,
550 struct smbsrv_request *req, struct smb_seek *io)
552 struct cvfs_private *private = ntvfs->private_data;
553 struct smbcli_request *c_req;
557 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
558 return smb_raw_seek(private->tree, io);
561 c_req = smb_raw_seek_send(private->tree, io);
569 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs,
570 struct smbsrv_request *req, struct smb_flush *io)
572 struct cvfs_private *private = ntvfs->private_data;
573 struct smbcli_request *c_req;
577 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
578 return smb_raw_flush(private->tree, io);
581 c_req = smb_raw_flush_send(private->tree, io);
589 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs,
590 struct smbsrv_request *req, union smb_close *io)
592 struct cvfs_private *private = ntvfs->private_data;
593 struct smbcli_request *c_req;
597 if (io->generic.level != RAW_CLOSE_GENERIC &&
598 private->map_generic) {
599 return ntvfs_map_close(req, io, ntvfs);
602 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
603 return smb_raw_close(private->tree, io);
606 c_req = smb_raw_close_send(private->tree, io);
612 exit - closing files open by the pid
614 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs,
615 struct smbsrv_request *req)
617 struct cvfs_private *private = ntvfs->private_data;
618 struct smbcli_request *c_req;
622 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
623 return smb_raw_exit(private->tree->session);
626 c_req = smb_raw_exit_send(private->tree->session);
632 logoff - closing files open by the user
634 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs,
635 struct smbsrv_request *req)
637 /* we can't do this right in the cifs backend .... */
642 setup for an async call - nothing to do yet
644 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs,
645 struct smbsrv_request *req,
654 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs,
655 struct smbsrv_request *req, union smb_lock *lck)
657 struct cvfs_private *private = ntvfs->private_data;
658 struct smbcli_request *c_req;
662 if (lck->generic.level != RAW_LOCK_GENERIC &&
663 private->map_generic) {
664 return ntvfs_map_lock(req, lck, ntvfs);
667 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
668 return smb_raw_lock(private->tree, lck);
671 c_req = smb_raw_lock_send(private->tree, lck);
676 set info on a open file
678 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
679 struct smbsrv_request *req,
680 union smb_setfileinfo *info)
682 struct cvfs_private *private = ntvfs->private_data;
683 struct smbcli_request *c_req;
687 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
688 return smb_raw_setfileinfo(private->tree, info);
690 c_req = smb_raw_setfileinfo_send(private->tree, info);
697 a handler for async fsinfo replies
699 static void async_fsinfo(struct smbcli_request *c_req)
701 struct async_info *async = c_req->async.private;
702 struct smbsrv_request *req = async->req;
703 req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms);
704 req->async_states->send_fn(req);
708 return filesystem space info
710 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs,
711 struct smbsrv_request *req, union smb_fsinfo *fs)
713 struct cvfs_private *private = ntvfs->private_data;
714 struct smbcli_request *c_req;
718 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
719 return smb_raw_fsinfo(private->tree, req, fs);
722 c_req = smb_raw_fsinfo_send(private->tree, req, fs);
724 ASYNC_RECV_TAIL(fs, async_fsinfo);
728 return print queue info
730 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs,
731 struct smbsrv_request *req, union smb_lpq *lpq)
733 return NT_STATUS_NOT_SUPPORTED;
737 list files in a directory matching a wildcard pattern
739 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs,
740 struct smbsrv_request *req, union smb_search_first *io,
741 void *search_private,
742 BOOL (*callback)(void *, union smb_search_data *))
744 struct cvfs_private *private = ntvfs->private_data;
748 return smb_raw_search_first(private->tree, req, io, search_private, callback);
751 /* continue a search */
752 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs,
753 struct smbsrv_request *req, union smb_search_next *io,
754 void *search_private,
755 BOOL (*callback)(void *, union smb_search_data *))
757 struct cvfs_private *private = ntvfs->private_data;
761 return smb_raw_search_next(private->tree, req, io, search_private, callback);
765 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs,
766 struct smbsrv_request *req, union smb_search_close *io)
768 struct cvfs_private *private = ntvfs->private_data;
772 return smb_raw_search_close(private->tree, io);
776 a handler for async trans2 replies
778 static void async_trans2(struct smbcli_request *c_req)
780 struct async_info *async = c_req->async.private;
781 struct smbsrv_request *req = async->req;
782 req->async_states->status = smb_raw_trans2_recv(c_req, req, async->parms);
783 req->async_states->send_fn(req);
787 static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs,
788 struct smbsrv_request *req, struct smb_trans2 *trans2)
790 struct cvfs_private *private = ntvfs->private_data;
791 struct smbcli_request *c_req;
795 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
796 return smb_raw_trans2(private->tree, req, trans2);
799 c_req = smb_raw_trans2_send(private->tree, trans2);
801 ASYNC_RECV_TAIL(trans2, async_trans2);
805 /* SMBtrans - not used on file shares */
806 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs,
807 struct smbsrv_request *req, struct smb_trans2 *trans2)
809 return NT_STATUS_ACCESS_DENIED;
813 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
815 NTSTATUS ntvfs_cifs_init(void)
818 struct ntvfs_ops ops;
822 /* fill in the name and type */
824 ops.type = NTVFS_DISK;
826 /* fill in all the operations */
827 ops.connect = cvfs_connect;
828 ops.disconnect = cvfs_disconnect;
829 ops.unlink = cvfs_unlink;
830 ops.chkpath = cvfs_chkpath;
831 ops.qpathinfo = cvfs_qpathinfo;
832 ops.setpathinfo = cvfs_setpathinfo;
833 ops.openfile = cvfs_open;
834 ops.mkdir = cvfs_mkdir;
835 ops.rmdir = cvfs_rmdir;
836 ops.rename = cvfs_rename;
837 ops.copy = cvfs_copy;
838 ops.ioctl = cvfs_ioctl;
839 ops.read = cvfs_read;
840 ops.write = cvfs_write;
841 ops.seek = cvfs_seek;
842 ops.flush = cvfs_flush;
843 ops.close = cvfs_close;
844 ops.exit = cvfs_exit;
845 ops.lock = cvfs_lock;
846 ops.setfileinfo = cvfs_setfileinfo;
847 ops.qfileinfo = cvfs_qfileinfo;
848 ops.fsinfo = cvfs_fsinfo;
850 ops.search_first = cvfs_search_first;
851 ops.search_next = cvfs_search_next;
852 ops.search_close = cvfs_search_close;
853 ops.trans = cvfs_trans;
854 ops.logoff = cvfs_logoff;
855 ops.async_setup = cvfs_async_setup;
857 if (lp_parm_bool(-1, "cifs", "maptrans2", False)) {
858 ops.trans2 = cvfs_trans2;
861 /* register ourselves with the NTVFS subsystem. We register
862 under the name 'cifs'. */
863 ret = register_backend("ntvfs", &ops);
865 if (!NT_STATUS_IS_OK(ret)) {
866 DEBUG(0,("Failed to register CIFS backend!\n"));