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;
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 int fd = socket_get_fd(private->tcon->smb_conn->connection->socket);
56 if (socket_pending(fd)) {
57 smbd_process_async(private->tcon->smb_conn);
62 a handler for oplock break events from the server - these need to be passed
65 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
67 struct cvfs_private *private = p_private;
69 DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
70 return req_send_oplock_break(private->tcon, fnum, level);
74 a handler for read events on a connection to a backend server
76 static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags)
78 struct cvfs_private *private = fde->private;
79 struct smbsrv_tcon *tcon = private->tcon;
81 DEBUG(5,("cifs_socket_handler event on fd %d\n", fde->fd));
83 if (!smbcli_transport_process(private->transport)) {
84 /* the connection to our server is dead */
90 connect to a share - used when a tree_connect operation comes in.
92 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
93 struct smbsrv_request *req, const char *sharename)
95 struct smbsrv_tcon *tcon = req->tcon;
97 struct cvfs_private *private;
98 const char *host, *user, *pass, *domain, *remote_share;
100 /* Here we need to determine which server to connect to.
101 * For now we use parametric options, type cifs.
102 * Later we will use security=server and auth_server.c.
104 host = lp_parm_string(req->tcon->service, "cifs", "server");
105 user = lp_parm_string(req->tcon->service, "cifs", "user");
106 pass = lp_parm_string(req->tcon->service, "cifs", "password");
107 domain = lp_parm_string(req->tcon->service, "cifs", "domain");
108 remote_share = lp_parm_string(req->tcon->service, "cifs", "share");
110 remote_share = sharename;
113 if (!host || !user || !pass || !domain) {
114 DEBUG(1,("CIFS backend: You must supply server, user, password and domain\n"));
115 return NT_STATUS_INVALID_PARAMETER;
118 private = talloc(req->tcon, sizeof(struct cvfs_private));
120 return NT_STATUS_NO_MEMORY;
122 ZERO_STRUCTP(private);
124 ntvfs->private_data = private;
126 status = smbcli_tree_full_connection(private,
131 remote_share, "?????",
134 if (!NT_STATUS_IS_OK(status)) {
138 private->transport = private->tree->session->transport;
139 private->tree->session->pid = SVAL(req->in.hdr, HDR_PID);
140 private->tcon = req->tcon;
142 tcon->fs_type = talloc_strdup(tcon, "NTFS");
143 tcon->dev_type = talloc_strdup(tcon, "A:");
145 /* we need to receive oplock break requests from the server */
146 smbcli_oplock_handler(private->transport, oplock_handler, private);
147 smbcli_transport_idle_handler(private->transport, idle_func, 1, private);
149 private->transport->event.fde->handler = cifs_socket_handler;
150 private->transport->event.fde->private = private;
152 private->transport->event.ctx = event_context_merge(tcon->smb_conn->connection->event.ctx,
153 private->transport->event.ctx);
154 talloc_reference(private, private->transport->event.ctx);
155 private->map_generic = lp_parm_bool(req->tcon->service,
156 "cifs", "mapgeneric", False);
162 disconnect from a share
164 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs,
165 struct smbsrv_tcon *tcon)
167 struct cvfs_private *private = ntvfs->private_data;
169 smb_tree_disconnect(private->tree);
170 talloc_free(private->tree);
176 a handler for simple async replies
177 this handler can only be used for functions that don't return any
178 parameters (those that just return a status code)
180 static void async_simple(struct smbcli_request *c_req)
182 struct async_info *async = c_req->async.private;
183 struct smbsrv_request *req = async->req;
184 req->async.status = smbcli_request_simple_recv(c_req);
185 req->async.send_fn(req);
189 /* save some typing for the simple functions */
190 #define ASYNC_RECV_TAIL(io, async_fn) do { \
191 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
193 struct async_info *async; \
194 async = talloc_p(req, struct async_info); \
195 if (!async) return NT_STATUS_NO_MEMORY; \
198 c_req->async.private = async; \
200 c_req->async.fn = async_fn; \
201 req->control_flags |= REQ_CONTROL_ASYNC; \
202 return NT_STATUS_OK; \
205 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
208 delete a file - the dirtype specifies the file types to include in the search.
209 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
211 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs,
212 struct smbsrv_request *req, struct smb_unlink *unl)
214 struct cvfs_private *private = ntvfs->private_data;
215 struct smbcli_request *c_req;
217 /* see if the front end will allow us to perform this
218 function asynchronously. */
219 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
220 return smb_raw_unlink(private->tree, unl);
223 c_req = smb_raw_unlink_send(private->tree, unl);
229 a handler for async ioctl replies
231 static void async_ioctl(struct smbcli_request *c_req)
233 struct async_info *async = c_req->async.private;
234 struct smbsrv_request *req = async->req;
235 req->async.status = smb_raw_ioctl_recv(c_req, req, async->parms);
236 req->async.send_fn(req);
242 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs,
243 struct smbsrv_request *req, union smb_ioctl *io)
245 struct cvfs_private *private = ntvfs->private_data;
246 struct smbcli_request *c_req;
248 /* see if the front end will allow us to perform this
249 function asynchronously. */
250 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
251 return smb_raw_ioctl(private->tree, req, io);
254 c_req = smb_raw_ioctl_send(private->tree, io);
256 ASYNC_RECV_TAIL(io, async_ioctl);
260 check if a directory exists
262 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs,
263 struct smbsrv_request *req, struct smb_chkpath *cp)
265 struct cvfs_private *private = ntvfs->private_data;
266 struct smbcli_request *c_req;
268 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
269 return smb_raw_chkpath(private->tree, cp);
272 c_req = smb_raw_chkpath_send(private->tree, cp);
278 a handler for async qpathinfo replies
280 static void async_qpathinfo(struct smbcli_request *c_req)
282 struct async_info *async = c_req->async.private;
283 struct smbsrv_request *req = async->req;
284 req->async.status = smb_raw_pathinfo_recv(c_req, req, async->parms);
285 req->async.send_fn(req);
289 return info on a pathname
291 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
292 struct smbsrv_request *req, union smb_fileinfo *info)
294 struct cvfs_private *private = ntvfs->private_data;
295 struct smbcli_request *c_req;
297 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
298 return smb_raw_pathinfo(private->tree, req, info);
301 c_req = smb_raw_pathinfo_send(private->tree, info);
303 ASYNC_RECV_TAIL(info, async_qpathinfo);
307 a handler for async qfileinfo replies
309 static void async_qfileinfo(struct smbcli_request *c_req)
311 struct async_info *async = c_req->async.private;
312 struct smbsrv_request *req = async->req;
313 req->async.status = smb_raw_fileinfo_recv(c_req, req, async->parms);
314 req->async.send_fn(req);
318 query info on a open file
320 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
321 struct smbsrv_request *req, union smb_fileinfo *info)
323 struct cvfs_private *private = ntvfs->private_data;
324 struct smbcli_request *c_req;
326 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
327 return smb_raw_fileinfo(private->tree, req, info);
330 c_req = smb_raw_fileinfo_send(private->tree, info);
332 ASYNC_RECV_TAIL(info, async_qfileinfo);
337 set info on a pathname
339 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
340 struct smbsrv_request *req, union smb_setfileinfo *st)
342 struct cvfs_private *private = ntvfs->private_data;
343 struct smbcli_request *c_req;
345 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
346 return smb_raw_setpathinfo(private->tree, st);
349 c_req = smb_raw_setpathinfo_send(private->tree, st);
356 a handler for async open replies
358 static void async_open(struct smbcli_request *c_req)
360 struct async_info *async = c_req->async.private;
361 struct smbsrv_request *req = async->req;
362 req->async.status = smb_raw_open_recv(c_req, req, async->parms);
363 req->async.send_fn(req);
369 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs,
370 struct smbsrv_request *req, union smb_open *io)
372 struct cvfs_private *private = ntvfs->private_data;
373 struct smbcli_request *c_req;
375 if (io->generic.level != RAW_OPEN_GENERIC &&
376 private->map_generic) {
377 return ntvfs_map_open(req, io, ntvfs);
380 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
381 return smb_raw_open(private->tree, req, io);
384 c_req = smb_raw_open_send(private->tree, io);
386 ASYNC_RECV_TAIL(io, async_open);
392 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs,
393 struct smbsrv_request *req, union smb_mkdir *md)
395 struct cvfs_private *private = ntvfs->private_data;
396 struct smbcli_request *c_req;
398 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
399 return smb_raw_mkdir(private->tree, md);
402 c_req = smb_raw_mkdir_send(private->tree, md);
410 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs,
411 struct smbsrv_request *req, struct smb_rmdir *rd)
413 struct cvfs_private *private = ntvfs->private_data;
414 struct smbcli_request *c_req;
416 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
417 return smb_raw_rmdir(private->tree, rd);
419 c_req = smb_raw_rmdir_send(private->tree, rd);
425 rename a set of files
427 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs,
428 struct smbsrv_request *req, union smb_rename *ren)
430 struct cvfs_private *private = ntvfs->private_data;
431 struct smbcli_request *c_req;
433 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
434 return smb_raw_rename(private->tree, ren);
437 c_req = smb_raw_rename_send(private->tree, ren);
445 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs,
446 struct smbsrv_request *req, struct smb_copy *cp)
448 return NT_STATUS_NOT_SUPPORTED;
452 a handler for async read replies
454 static void async_read(struct smbcli_request *c_req)
456 struct async_info *async = c_req->async.private;
457 struct smbsrv_request *req = async->req;
458 req->async.status = smb_raw_read_recv(c_req, async->parms);
459 req->async.send_fn(req);
465 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs,
466 struct smbsrv_request *req, union smb_read *rd)
468 struct cvfs_private *private = ntvfs->private_data;
469 struct smbcli_request *c_req;
471 if (rd->generic.level != RAW_READ_GENERIC &&
472 private->map_generic) {
473 return ntvfs_map_read(req, rd, ntvfs);
476 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
477 return smb_raw_read(private->tree, rd);
480 c_req = smb_raw_read_send(private->tree, rd);
482 ASYNC_RECV_TAIL(rd, async_read);
486 a handler for async write replies
488 static void async_write(struct smbcli_request *c_req)
490 struct async_info *async = c_req->async.private;
491 struct smbsrv_request *req = async->req;
492 req->async.status = smb_raw_write_recv(c_req, async->parms);
493 req->async.send_fn(req);
499 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs,
500 struct smbsrv_request *req, union smb_write *wr)
502 struct cvfs_private *private = ntvfs->private_data;
503 struct smbcli_request *c_req;
505 if (wr->generic.level != RAW_WRITE_GENERIC &&
506 private->map_generic) {
507 return ntvfs_map_write(req, wr, ntvfs);
510 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
511 return smb_raw_write(private->tree, wr);
514 c_req = smb_raw_write_send(private->tree, wr);
516 ASYNC_RECV_TAIL(wr, async_write);
522 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs,
523 struct smbsrv_request *req, struct smb_seek *io)
525 struct cvfs_private *private = ntvfs->private_data;
526 struct smbcli_request *c_req;
528 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
529 return smb_raw_seek(private->tree, io);
532 c_req = smb_raw_seek_send(private->tree, io);
540 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs,
541 struct smbsrv_request *req, struct smb_flush *io)
543 struct cvfs_private *private = ntvfs->private_data;
544 struct smbcli_request *c_req;
546 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
547 return smb_raw_flush(private->tree, io);
550 c_req = smb_raw_flush_send(private->tree, io);
558 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs,
559 struct smbsrv_request *req, union smb_close *io)
561 struct cvfs_private *private = ntvfs->private_data;
562 struct smbcli_request *c_req;
564 if (io->generic.level != RAW_CLOSE_GENERIC &&
565 private->map_generic) {
566 return ntvfs_map_close(req, io, ntvfs);
569 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
570 return smb_raw_close(private->tree, io);
573 c_req = smb_raw_close_send(private->tree, io);
579 exit - closing files open by the pid
581 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs,
582 struct smbsrv_request *req)
584 struct cvfs_private *private = ntvfs->private_data;
585 struct smbcli_request *c_req;
587 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
588 return smb_raw_exit(private->tree->session);
591 c_req = smb_raw_exit_send(private->tree->session);
597 logoff - closing files open by the user
599 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs,
600 struct smbsrv_request *req)
602 /* we can't do this right in the cifs backend .... */
607 setup for an async call - nothing to do yet
609 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs,
610 struct smbsrv_request *req,
619 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs,
620 struct smbsrv_request *req, union smb_lock *lck)
622 struct cvfs_private *private = ntvfs->private_data;
623 struct smbcli_request *c_req;
625 if (lck->generic.level != RAW_LOCK_GENERIC &&
626 private->map_generic) {
627 return ntvfs_map_lock(req, lck, ntvfs);
630 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
631 return smb_raw_lock(private->tree, lck);
634 c_req = smb_raw_lock_send(private->tree, lck);
639 set info on a open file
641 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
642 struct smbsrv_request *req,
643 union smb_setfileinfo *info)
645 struct cvfs_private *private = ntvfs->private_data;
646 struct smbcli_request *c_req;
648 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
649 return smb_raw_setfileinfo(private->tree, info);
651 c_req = smb_raw_setfileinfo_send(private->tree, info);
658 a handler for async fsinfo replies
660 static void async_fsinfo(struct smbcli_request *c_req)
662 struct async_info *async = c_req->async.private;
663 struct smbsrv_request *req = async->req;
664 req->async.status = smb_raw_fsinfo_recv(c_req, req, async->parms);
665 req->async.send_fn(req);
669 return filesystem space info
671 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs,
672 struct smbsrv_request *req, union smb_fsinfo *fs)
674 struct cvfs_private *private = ntvfs->private_data;
675 struct smbcli_request *c_req;
677 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
678 return smb_raw_fsinfo(private->tree, req, fs);
681 c_req = smb_raw_fsinfo_send(private->tree, req, fs);
683 ASYNC_RECV_TAIL(fs, async_fsinfo);
687 return print queue info
689 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs,
690 struct smbsrv_request *req, union smb_lpq *lpq)
692 return NT_STATUS_NOT_SUPPORTED;
696 list files in a directory matching a wildcard pattern
698 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs,
699 struct smbsrv_request *req, union smb_search_first *io,
700 void *search_private,
701 BOOL (*callback)(void *, union smb_search_data *))
703 struct cvfs_private *private = ntvfs->private_data;
705 return smb_raw_search_first(private->tree, req, io, search_private, callback);
708 /* continue a search */
709 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs,
710 struct smbsrv_request *req, union smb_search_next *io,
711 void *search_private,
712 BOOL (*callback)(void *, union smb_search_data *))
714 struct cvfs_private *private = ntvfs->private_data;
716 return smb_raw_search_next(private->tree, req, io, search_private, callback);
720 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs,
721 struct smbsrv_request *req, union smb_search_close *io)
723 struct cvfs_private *private = ntvfs->private_data;
725 return smb_raw_search_close(private->tree, io);
729 a handler for async trans2 replies
731 static void async_trans2(struct smbcli_request *c_req)
733 struct async_info *async = c_req->async.private;
734 struct smbsrv_request *req = async->req;
735 req->async.status = smb_raw_trans2_recv(c_req, req, async->parms);
736 req->async.send_fn(req);
740 static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs,
741 struct smbsrv_request *req, struct smb_trans2 *trans2)
743 struct cvfs_private *private = ntvfs->private_data;
744 struct smbcli_request *c_req;
746 if (!(req->control_flags & REQ_CONTROL_MAY_ASYNC)) {
747 return smb_raw_trans2(private->tree, req, trans2);
750 c_req = smb_raw_trans2_send(private->tree, trans2);
752 ASYNC_RECV_TAIL(trans2, async_trans2);
756 /* SMBtrans - not used on file shares */
757 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs,
758 struct smbsrv_request *req, struct smb_trans2 *trans2)
760 return NT_STATUS_ACCESS_DENIED;
764 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
766 NTSTATUS ntvfs_cifs_init(void)
769 struct ntvfs_ops ops;
773 /* fill in the name and type */
775 ops.type = NTVFS_DISK;
777 /* fill in all the operations */
778 ops.connect = cvfs_connect;
779 ops.disconnect = cvfs_disconnect;
780 ops.unlink = cvfs_unlink;
781 ops.chkpath = cvfs_chkpath;
782 ops.qpathinfo = cvfs_qpathinfo;
783 ops.setpathinfo = cvfs_setpathinfo;
784 ops.open = cvfs_open;
785 ops.mkdir = cvfs_mkdir;
786 ops.rmdir = cvfs_rmdir;
787 ops.rename = cvfs_rename;
788 ops.copy = cvfs_copy;
789 ops.ioctl = cvfs_ioctl;
790 ops.read = cvfs_read;
791 ops.write = cvfs_write;
792 ops.seek = cvfs_seek;
793 ops.flush = cvfs_flush;
794 ops.close = cvfs_close;
795 ops.exit = cvfs_exit;
796 ops.lock = cvfs_lock;
797 ops.setfileinfo = cvfs_setfileinfo;
798 ops.qfileinfo = cvfs_qfileinfo;
799 ops.fsinfo = cvfs_fsinfo;
801 ops.search_first = cvfs_search_first;
802 ops.search_next = cvfs_search_next;
803 ops.search_close = cvfs_search_close;
804 ops.trans = cvfs_trans;
805 ops.logoff = cvfs_logoff;
806 ops.async_setup = cvfs_async_setup;
808 if (lp_parm_bool(-1, "cifs", "maptrans2", False)) {
809 ops.trans2 = cvfs_trans2;
812 /* register ourselves with the NTVFS subsystem. We register
813 under the name 'cifs'. */
814 ret = register_backend("ntvfs", &ops);
816 if (!NT_STATUS_IS_OK(ret)) {
817 DEBUG(0,("Failed to register CIFS backend!\n"));