root/source4/ntvfs/smb2/vfs_smb2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. oplock_handler
  2. smb2_get_roothandle
  3. cvfs_connect
  4. cvfs_disconnect
  5. async_info_destructor
  6. async_simple_smb2
  7. async_simple_composite
  8. cvfs_unlink
  9. cvfs_ioctl
  10. cvfs_chkpath
  11. cvfs_qpathinfo
  12. cvfs_qfileinfo
  13. cvfs_setpathinfo
  14. cvfs_open
  15. cvfs_mkdir
  16. cvfs_rmdir
  17. cvfs_rename
  18. cvfs_copy
  19. cvfs_read
  20. cvfs_write
  21. cvfs_seek
  22. cvfs_flush
  23. cvfs_close
  24. cvfs_exit
  25. cvfs_logoff
  26. cvfs_async_setup
  27. cvfs_cancel
  28. cvfs_lock
  29. cvfs_setfileinfo
  30. async_fsinfo
  31. cvfs_fsinfo
  32. cvfs_lpq
  33. cvfs_search_first
  34. cvfs_search_next
  35. cvfs_search_close
  36. cvfs_trans
  37. cvfs_notify
  38. ntvfs_smb2_init

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    CIFS-to-SMB2 NTVFS filesystem backend
   5 
   6    Copyright (C) Andrew Tridgell 2008
   7 
   8    largely based on vfs_cifs.c which was 
   9       Copyright (C) Andrew Tridgell 2003
  10       Copyright (C) James J Myers 2003 <myersjj@samba.org>
  11 
  12    This program is free software; you can redistribute it and/or modify
  13    it under the terms of the GNU General Public License as published by
  14    the Free Software Foundation; either version 3 of the License, or
  15    (at your option) any later version.
  16    
  17    This program is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20    GNU General Public License for more details.
  21    
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  24 */
  25 /*
  26   this implements a CIFS->CIFS NTVFS filesystem backend. 
  27   
  28 */
  29 
  30 #include "includes.h"
  31 #include "libcli/raw/libcliraw.h"
  32 #include "libcli/raw/raw_proto.h"
  33 #include "libcli/composite/composite.h"
  34 #include "libcli/smb_composite/smb_composite.h"
  35 #include "auth/auth.h"
  36 #include "auth/credentials/credentials.h"
  37 #include "ntvfs/ntvfs.h"
  38 #include "../lib/util/dlinklist.h"
  39 #include "param/param.h"
  40 #include "libcli/resolve/resolve.h"
  41 #include "libcli/smb2/smb2.h"
  42 #include "libcli/smb2/smb2_calls.h"
  43 
  44 struct cvfs_file {
  45         struct cvfs_file *prev, *next;
  46         uint16_t fnum;
  47         struct ntvfs_handle *h;
  48 };
  49 
  50 /* this is stored in ntvfs_private */
  51 struct cvfs_private {
  52         struct smb2_tree *tree;
  53         struct smb2_transport *transport;
  54         struct ntvfs_module_context *ntvfs;
  55         struct async_info *pending;
  56         struct cvfs_file *files;
  57 
  58         /* a handle on the root of the share */
  59         /* TODO: leaving this handle open could prevent other users
  60            from opening the share with exclusive access. We probably
  61            need to open it on demand */
  62         struct smb2_handle roothandle;
  63 };
  64 
  65 
  66 /* a structure used to pass information to an async handler */
  67 struct async_info {
  68         struct async_info *next, *prev;
  69         struct cvfs_private *cvfs;
  70         struct ntvfs_request *req;
  71         void *c_req;
  72         struct composite_context *c_comp;
  73         struct cvfs_file *f;
  74         void *parms;
  75 };
  76 
  77 #define SETUP_FILE_HERE(f) do { \
  78         f = ntvfs_handle_get_backend_data(io->generic.in.file.ntvfs, ntvfs); \
  79         if (!f) return NT_STATUS_INVALID_HANDLE; \
  80         io->generic.in.file.fnum = f->fnum; \
  81 } while (0)
  82 
  83 #define SETUP_FILE do { \
  84         struct cvfs_file *f; \
  85         SETUP_FILE_HERE(f); \
  86 } while (0)
  87 
  88 #define SMB2_SERVER             "smb2:server"
  89 #define SMB2_USER               "smb2:user"
  90 #define SMB2_PASSWORD           "smb2:password"
  91 #define SMB2_DOMAIN             "smb2:domain"
  92 #define SMB2_SHARE              "smb2:share"
  93 #define SMB2_USE_MACHINE_ACCT   "smb2:use-machine-account"
  94 
  95 #define SMB2_USE_MACHINE_ACCT_DEFAULT   false
  96 
  97 /*
  98   a handler for oplock break events from the server - these need to be passed
  99   along to the client
 100  */
 101 static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
     /* [<][>][^][v][top][bottom][index][help] */
 102 {
 103         struct cvfs_private *p = p_private;
 104         NTSTATUS status;
 105         struct ntvfs_handle *h = NULL;
 106         struct cvfs_file *f;
 107 
 108         for (f=p->files; f; f=f->next) {
 109                 if (f->fnum != fnum) continue;
 110                 h = f->h;
 111                 break;
 112         }
 113 
 114         if (!h) {
 115                 DEBUG(5,("vfs_smb2: ignoring oplock break level %d for fnum %d\n", level, fnum));
 116                 return true;
 117         }
 118 
 119         DEBUG(5,("vfs_smb2: sending oplock break level %d for fnum %d\n", level, fnum));
 120         status = ntvfs_send_oplock_break(p->ntvfs, h, level);
 121         if (!NT_STATUS_IS_OK(status)) return false;
 122         return true;
 123 }
 124 
 125 /*
 126   return a handle to the root of the share
 127 */
 128 static NTSTATUS smb2_get_roothandle(struct smb2_tree *tree, struct smb2_handle *handle)
     /* [<][>][^][v][top][bottom][index][help] */
 129 {
 130         struct smb2_create io;
 131         NTSTATUS status;
 132 
 133         ZERO_STRUCT(io);
 134         io.in.oplock_level = 0;
 135         io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
 136         io.in.file_attributes   = 0;
 137         io.in.create_disposition = NTCREATEX_DISP_OPEN;
 138         io.in.share_access = 
 139                 NTCREATEX_SHARE_ACCESS_READ |
 140                 NTCREATEX_SHARE_ACCESS_WRITE|
 141                 NTCREATEX_SHARE_ACCESS_DELETE;
 142         io.in.create_options = 0;
 143         io.in.fname = NULL;
 144 
 145         status = smb2_create(tree, tree, &io);
 146         NT_STATUS_NOT_OK_RETURN(status);
 147 
 148         *handle = io.out.file.handle;
 149 
 150         return NT_STATUS_OK;
 151 }
 152 
 153 /*
 154   connect to a share - used when a tree_connect operation comes in.
 155 */
 156 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 157                              struct ntvfs_request *req, const char *sharename)
 158 {
 159         NTSTATUS status;
 160         struct cvfs_private *p;
 161         const char *host, *user, *pass, *domain, *remote_share;
 162         struct composite_context *creq;
 163         struct share_config *scfg = ntvfs->ctx->config;
 164         struct smb2_tree *tree;
 165         struct cli_credentials *credentials;
 166         bool machine_account;
 167         struct smbcli_options options;
 168 
 169         /* Here we need to determine which server to connect to.
 170          * For now we use parametric options, type cifs.
 171          * Later we will use security=server and auth_server.c.
 172          */
 173         host = share_string_option(scfg, SMB2_SERVER, NULL);
 174         user = share_string_option(scfg, SMB2_USER, NULL);
 175         pass = share_string_option(scfg, SMB2_PASSWORD, NULL);
 176         domain = share_string_option(scfg, SMB2_DOMAIN, NULL);
 177         remote_share = share_string_option(scfg, SMB2_SHARE, NULL);
 178         if (!remote_share) {
 179                 remote_share = sharename;
 180         }
 181 
 182         machine_account = share_bool_option(scfg, SMB2_USE_MACHINE_ACCT, SMB2_USE_MACHINE_ACCT_DEFAULT);
 183 
 184         p = talloc_zero(ntvfs, struct cvfs_private);
 185         if (!p) {
 186                 return NT_STATUS_NO_MEMORY;
 187         }
 188 
 189         ntvfs->private_data = p;
 190 
 191         if (!host) {
 192                 DEBUG(1,("CIFS backend: You must supply server\n"));
 193                 return NT_STATUS_INVALID_PARAMETER;
 194         } 
 195         
 196         if (user && pass) {
 197                 DEBUG(5, ("CIFS backend: Using specified password\n"));
 198                 credentials = cli_credentials_init(p);
 199                 if (!credentials) {
 200                         return NT_STATUS_NO_MEMORY;
 201                 }
 202                 cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx);
 203                 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
 204                 if (domain) {
 205                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
 206                 }
 207                 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
 208         } else if (machine_account) {
 209                 DEBUG(5, ("CIFS backend: Using machine account\n"));
 210                 credentials = cli_credentials_init(p);
 211                 cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx);
 212                 if (domain) {
 213                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
 214                 }
 215                 status = cli_credentials_set_machine_account(credentials, ntvfs->ctx->lp_ctx);
 216                 if (!NT_STATUS_IS_OK(status)) {
 217                         return status;
 218                 }
 219         } else if (req->session_info->credentials) {
 220                 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
 221                 credentials = req->session_info->credentials;
 222         } else {
 223                 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
 224                 return NT_STATUS_INVALID_PARAMETER;
 225         }
 226 
 227         lp_smbcli_options(ntvfs->ctx->lp_ctx, &options);
 228 
 229         creq = smb2_connect_send(p, host,
 230                         lp_parm_string_list(p, ntvfs->ctx->lp_ctx, NULL, "smb2", "ports", NULL),
 231                                 remote_share, 
 232                                  lp_resolve_context(ntvfs->ctx->lp_ctx),
 233                                  credentials,
 234                                  ntvfs->ctx->event_ctx, &options,
 235                                  lp_socket_options(ntvfs->ctx->lp_ctx),
 236                                  lp_gensec_settings(p, ntvfs->ctx->lp_ctx)
 237                                  );
 238 
 239         status = smb2_connect_recv(creq, p, &tree);
 240         NT_STATUS_NOT_OK_RETURN(status);
 241 
 242         status = smb2_get_roothandle(tree, &p->roothandle);
 243         NT_STATUS_NOT_OK_RETURN(status);
 244 
 245         p->tree = tree;
 246         p->transport = p->tree->session->transport;
 247         p->ntvfs = ntvfs;
 248 
 249         ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
 250         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
 251         ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
 252         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
 253 
 254         /* we need to receive oplock break requests from the server */
 255         /* TODO: enable oplocks 
 256         smbcli_oplock_handler(p->transport, oplock_handler, p);
 257         */
 258         return NT_STATUS_OK;
 259 }
 260 
 261 /*
 262   disconnect from a share
 263 */
 264 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs)
     /* [<][>][^][v][top][bottom][index][help] */
 265 {
 266         struct cvfs_private *p = ntvfs->private_data;
 267         struct async_info *a, *an;
 268 
 269         /* first cleanup pending requests */
 270         for (a=p->pending; a; a = an) {
 271                 an = a->next;
 272                 talloc_free(a->c_req);
 273                 talloc_free(a);
 274         }
 275 
 276         talloc_free(p);
 277         ntvfs->private_data = NULL;
 278 
 279         return NT_STATUS_OK;
 280 }
 281 
 282 /*
 283   destroy an async info structure
 284 */
 285 static int async_info_destructor(struct async_info *async)
     /* [<][>][^][v][top][bottom][index][help] */
 286 {
 287         DLIST_REMOVE(async->cvfs->pending, async);
 288         return 0;
 289 }
 290 
 291 /*
 292   a handler for simple async SMB2 replies
 293   this handler can only be used for functions that don't return any
 294   parameters (those that just return a status code)
 295  */
 296 static void async_simple_smb2(struct smb2_request *c_req)
     /* [<][>][^][v][top][bottom][index][help] */
 297 {
 298         struct async_info *async = c_req->async.private_data;
 299         struct ntvfs_request *req = async->req;
 300 
 301         smb2_request_receive(c_req);
 302         req->async_states->status = smb2_request_destroy(c_req);
 303         talloc_free(async);
 304         req->async_states->send_fn(req);
 305 }
 306 
 307 /*
 308   a handler for simple async composite replies
 309   this handler can only be used for functions that don't return any
 310   parameters (those that just return a status code)
 311  */
 312 static void async_simple_composite(struct composite_context *c_req)
     /* [<][>][^][v][top][bottom][index][help] */
 313 {
 314         struct async_info *async = c_req->async.private_data;
 315         struct ntvfs_request *req = async->req;
 316 
 317         req->async_states->status = composite_wait_free(c_req);
 318         talloc_free(async);
 319         req->async_states->send_fn(req);
 320 }
 321 
 322 
 323 /* save some typing for the simple functions */
 324 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
 325         if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
 326         { \
 327                 struct async_info *async; \
 328                 async = talloc(req, struct async_info); \
 329                 if (!async) return NT_STATUS_NO_MEMORY; \
 330                 async->parms = io; \
 331                 async->req = req; \
 332                 async->f = file; \
 333                 async->cvfs = p; \
 334                 async->c_req = c_req; \
 335                 DLIST_ADD(p->pending, async); \
 336                 c_req->async.private_data = async; \
 337                 talloc_set_destructor(async, async_info_destructor); \
 338         } \
 339         c_req->async.fn = async_fn; \
 340         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
 341         return NT_STATUS_OK; \
 342 } while (0)
 343 
 344 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
 345 
 346 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple_smb2)
 347 #define SIMPLE_COMPOSITE_TAIL ASYNC_RECV_TAIL(NULL, async_simple_composite)
 348 
 349 #define CHECK_ASYNC(req) do { \
 350         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { \
 351                 DEBUG(0,("SMB2 proxy backend does not support sync operation at %s\n", \
 352                          __location__)); \
 353                 return NT_STATUS_NOT_IMPLEMENTED; \
 354         }} while (0)
 355 
 356 /*
 357   delete a file - the dirtype specifies the file types to include in the search. 
 358   The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
 359 
 360   BUGS:
 361      - doesn't handle wildcards
 362      - doesn't obey attrib restrictions
 363 */
 364 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 365                             struct ntvfs_request *req, union smb_unlink *unl)
 366 {
 367         struct cvfs_private *p = ntvfs->private_data;
 368         struct composite_context *c_req;
 369 
 370         CHECK_ASYNC(req);
 371 
 372         c_req = smb2_composite_unlink_send(p->tree, unl);
 373 
 374         SIMPLE_COMPOSITE_TAIL;
 375 }
 376 
 377 /*
 378   ioctl interface
 379 */
 380 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 381                            struct ntvfs_request *req, union smb_ioctl *io)
 382 {
 383         return NT_STATUS_NOT_IMPLEMENTED;
 384 }
 385 
 386 /*
 387   check if a directory exists
 388 */
 389 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 390                              struct ntvfs_request *req, union smb_chkpath *cp)
 391 {
 392         struct cvfs_private *p = ntvfs->private_data;
 393         struct smb2_request *c_req;
 394         struct smb2_find f;
 395 
 396         CHECK_ASYNC(req);
 397         
 398         /* SMB2 doesn't have a chkpath operation, and also doesn't
 399          have a query path info call, so the best seems to be to do a
 400          find call, using the roothandle we established at connect
 401          time */
 402         ZERO_STRUCT(f);
 403         f.in.file.handle        = p->roothandle;
 404         f.in.level              = SMB2_FIND_DIRECTORY_INFO;
 405         f.in.pattern            = cp->chkpath.in.path;
 406         /* SMB2 find doesn't accept \ or the empty string - this is the best
 407            approximation */
 408         if (strcmp(f.in.pattern, "\\") == 0 || 
 409             strcmp(f.in.pattern, "") == 0) {
 410                 f.in.pattern            = "?";
 411         }
 412         f.in.continue_flags     = SMB2_CONTINUE_FLAG_SINGLE | SMB2_CONTINUE_FLAG_RESTART;
 413         f.in.max_response_size  = 0x1000;
 414         
 415         c_req = smb2_find_send(p->tree, &f);
 416 
 417         SIMPLE_ASYNC_TAIL;
 418 }
 419 
 420 /*
 421   return info on a pathname
 422 */
 423 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 424                                struct ntvfs_request *req, union smb_fileinfo *info)
 425 {
 426         return NT_STATUS_NOT_IMPLEMENTED;
 427 }
 428 
 429 /*
 430   query info on a open file
 431 */
 432 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 433                                struct ntvfs_request *req, union smb_fileinfo *io)
 434 {
 435         return NT_STATUS_NOT_IMPLEMENTED;
 436 }
 437 
 438 
 439 /*
 440   set info on a pathname
 441 */
 442 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 443                                  struct ntvfs_request *req, union smb_setfileinfo *st)
 444 {
 445         return NT_STATUS_NOT_IMPLEMENTED;
 446 }
 447 
 448 
 449 /*
 450   open a file
 451 */
 452 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 453                           struct ntvfs_request *req, union smb_open *io)
 454 {
 455         return NT_STATUS_NOT_IMPLEMENTED;
 456 }
 457 
 458 /*
 459   create a directory
 460 */
 461 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 462                            struct ntvfs_request *req, union smb_mkdir *md)
 463 {
 464         struct cvfs_private *p = ntvfs->private_data;
 465         struct composite_context *c_req;
 466 
 467         CHECK_ASYNC(req);
 468 
 469         c_req = smb2_composite_mkdir_send(p->tree, md);
 470 
 471         SIMPLE_COMPOSITE_TAIL;
 472 }
 473 
 474 /*
 475   remove a directory
 476 */
 477 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 478                            struct ntvfs_request *req, struct smb_rmdir *rd)
 479 {
 480         struct cvfs_private *p = ntvfs->private_data;
 481         struct composite_context *c_req;
 482 
 483         CHECK_ASYNC(req);
 484 
 485         c_req = smb2_composite_rmdir_send(p->tree, rd);
 486 
 487         SIMPLE_COMPOSITE_TAIL;
 488 }
 489 
 490 /*
 491   rename a set of files
 492 */
 493 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 494                             struct ntvfs_request *req, union smb_rename *ren)
 495 {
 496         return NT_STATUS_NOT_IMPLEMENTED;
 497 }
 498 
 499 /*
 500   copy a set of files
 501 */
 502 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 503                           struct ntvfs_request *req, struct smb_copy *cp)
 504 {
 505         return NT_STATUS_NOT_SUPPORTED;
 506 }
 507 
 508 /*
 509   read from a file
 510 */
 511 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 512                           struct ntvfs_request *req, union smb_read *io)
 513 {
 514         return NT_STATUS_NOT_IMPLEMENTED;
 515 }
 516 
 517 /*
 518   write to a file
 519 */
 520 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 521                            struct ntvfs_request *req, union smb_write *io)
 522 {
 523         return NT_STATUS_NOT_IMPLEMENTED;
 524 }
 525 
 526 /*
 527   seek in a file
 528 */
 529 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 530                           struct ntvfs_request *req,
 531                           union smb_seek *io)
 532 {
 533         return NT_STATUS_NOT_IMPLEMENTED;
 534 }
 535 
 536 /*
 537   flush a file
 538 */
 539 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 540                            struct ntvfs_request *req,
 541                            union smb_flush *io)
 542 {
 543         return NT_STATUS_NOT_IMPLEMENTED;
 544 }
 545 
 546 /*
 547   close a file
 548 */
 549 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 550                            struct ntvfs_request *req, union smb_close *io)
 551 {
 552         return NT_STATUS_NOT_IMPLEMENTED;
 553 }
 554 
 555 /*
 556   exit - closing files open by the pid
 557 */
 558 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 559                           struct ntvfs_request *req)
 560 {
 561         return NT_STATUS_NOT_IMPLEMENTED;
 562 }
 563 
 564 /*
 565   logoff - closing files open by the user
 566 */
 567 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 568                             struct ntvfs_request *req)
 569 {
 570         /* we can't do this right in the cifs backend .... */
 571         return NT_STATUS_OK;
 572 }
 573 
 574 /*
 575   setup for an async call - nothing to do yet
 576 */
 577 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 578                                  struct ntvfs_request *req, 
 579                                  void *private_data)
 580 {
 581         return NT_STATUS_OK;
 582 }
 583 
 584 /*
 585   cancel an async call
 586 */
 587 static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 588                             struct ntvfs_request *req)
 589 {
 590         return NT_STATUS_NOT_IMPLEMENTED;
 591 }
 592 
 593 /*
 594   lock a byte range
 595 */
 596 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 597                           struct ntvfs_request *req, union smb_lock *io)
 598 {
 599         return NT_STATUS_NOT_IMPLEMENTED;
 600 }
 601 
 602 /*
 603   set info on a open file
 604 */
 605 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 606                                  struct ntvfs_request *req, 
 607                                  union smb_setfileinfo *io)
 608 {
 609         return NT_STATUS_NOT_IMPLEMENTED;
 610 }
 611 
 612 
 613 /*
 614   a handler for async fsinfo replies
 615  */
 616 static void async_fsinfo(struct smb2_request *c_req)
     /* [<][>][^][v][top][bottom][index][help] */
 617 {
 618         struct async_info *async = c_req->async.private_data;
 619         struct ntvfs_request *req = async->req;
 620         req->async_states->status = smb2_getinfo_fs_recv(c_req, req, async->parms);
 621         talloc_free(async);
 622         req->async_states->send_fn(req);
 623 }
 624 
 625 /*
 626   return filesystem space info
 627 */
 628 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 629                             struct ntvfs_request *req, union smb_fsinfo *fs)
 630 {
 631         struct cvfs_private *p = ntvfs->private_data;
 632         struct smb2_request *c_req;
 633         enum smb_fsinfo_level level = fs->generic.level;
 634 
 635         CHECK_ASYNC(req);
 636 
 637         switch (level) {
 638                 /* some levels go straight through */
 639         case RAW_QFS_VOLUME_INFORMATION:
 640         case RAW_QFS_SIZE_INFORMATION:
 641         case RAW_QFS_DEVICE_INFORMATION:
 642         case RAW_QFS_ATTRIBUTE_INFORMATION:
 643         case RAW_QFS_QUOTA_INFORMATION:
 644         case RAW_QFS_FULL_SIZE_INFORMATION:
 645         case RAW_QFS_OBJECTID_INFORMATION:
 646                 break;
 647 
 648                 /* some get mapped */
 649         case RAW_QFS_VOLUME_INFO:
 650                 level = RAW_QFS_VOLUME_INFORMATION;
 651                 break;
 652         case RAW_QFS_SIZE_INFO:
 653                 level = RAW_QFS_SIZE_INFORMATION;
 654                 break;
 655         case RAW_QFS_DEVICE_INFO:
 656                 level = RAW_QFS_DEVICE_INFORMATION;
 657                 break;
 658         case RAW_QFS_ATTRIBUTE_INFO:
 659                 level = RAW_QFS_ATTRIBUTE_INFO;
 660                 break;
 661 
 662         default:
 663                 /* the rest get refused for now */
 664                 DEBUG(0,("fsinfo level %u not possible on SMB2\n",
 665                          (unsigned)fs->generic.level));
 666                 break;
 667         }
 668 
 669         fs->generic.level = level;
 670         fs->generic.handle = p->roothandle;
 671 
 672         c_req = smb2_getinfo_fs_send(p->tree, fs);
 673 
 674         ASYNC_RECV_TAIL(fs, async_fsinfo);
 675 }
 676 
 677 /*
 678   return print queue info
 679 */
 680 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 681                          struct ntvfs_request *req, union smb_lpq *lpq)
 682 {
 683         return NT_STATUS_NOT_SUPPORTED;
 684 }
 685 
 686 /* 
 687    list files in a directory matching a wildcard pattern
 688 */
 689 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 690                                   struct ntvfs_request *req, union smb_search_first *io, 
 691                                   void *search_private, 
 692                                   bool (*callback)(void *, const union smb_search_data *))
 693 {
 694         struct cvfs_private *p = ntvfs->private_data;
 695         struct smb2_find f;
 696         enum smb_search_data_level smb2_level;
 697         uint_t count, i;
 698         union smb_search_data *data;
 699         NTSTATUS status;
 700 
 701         if (io->generic.level != RAW_SEARCH_TRANS2) {
 702                 DEBUG(0,("We only support trans2 search in smb2 backend\n"));
 703                 return NT_STATUS_NOT_SUPPORTED;
 704         }
 705 
 706         switch (io->generic.data_level) {
 707         case RAW_SEARCH_DATA_DIRECTORY_INFO:
 708                 smb2_level = SMB2_FIND_DIRECTORY_INFO;
 709                 break;
 710         case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
 711                 smb2_level = SMB2_FIND_FULL_DIRECTORY_INFO;
 712                 break;
 713         case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
 714                 smb2_level = SMB2_FIND_BOTH_DIRECTORY_INFO;
 715                 break;
 716         case RAW_SEARCH_DATA_NAME_INFO:
 717                 smb2_level = SMB2_FIND_NAME_INFO;
 718                 break;
 719         case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
 720                 smb2_level = SMB2_FIND_ID_FULL_DIRECTORY_INFO;
 721                 break;
 722         case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
 723                 smb2_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
 724                 break;
 725         default:
 726                 DEBUG(0,("Unsupported search level %u for smb2 backend\n",
 727                          (unsigned)io->generic.data_level));
 728                 return NT_STATUS_INVALID_INFO_CLASS;
 729         }
 730 
 731         /* we do the search on the roothandle. This only works because
 732            search is synchronous, otherwise we'd have no way to
 733            distinguish multiple searches happening at once
 734         */
 735         ZERO_STRUCT(f);
 736         f.in.file.handle        = p->roothandle;
 737         f.in.level              = smb2_level;
 738         f.in.pattern            = io->t2ffirst.in.pattern;
 739         while (f.in.pattern[0] == '\\') {
 740                 f.in.pattern++;
 741         }
 742         f.in.continue_flags     = 0;
 743         f.in.max_response_size  = 0x10000;
 744 
 745         status = smb2_find_level(p->tree, req, &f, &count, &data);
 746         NT_STATUS_NOT_OK_RETURN(status);        
 747 
 748         for (i=0;i<count;i++) {
 749                 if (!callback(search_private, &data[i])) break;
 750         }
 751 
 752         io->t2ffirst.out.handle = 0;
 753         io->t2ffirst.out.count = i;
 754         /* TODO: fix end_of_file */
 755         io->t2ffirst.out.end_of_search = 1;
 756 
 757         talloc_free(data);
 758         
 759         return NT_STATUS_OK;
 760 }
 761 
 762 /* continue a search */
 763 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 764                                  struct ntvfs_request *req, union smb_search_next *io, 
 765                                  void *search_private, 
 766                                  bool (*callback)(void *, const union smb_search_data *))
 767 {
 768         return NT_STATUS_NOT_IMPLEMENTED;
 769 }
 770 
 771 /* close a search */
 772 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 773                                   struct ntvfs_request *req, union smb_search_close *io)
 774 {
 775         return NT_STATUS_NOT_IMPLEMENTED;
 776 }
 777 
 778 /* SMBtrans - not used on file shares */
 779 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 780                            struct ntvfs_request *req,
 781                            struct smb_trans2 *trans2)
 782 {
 783         return NT_STATUS_ACCESS_DENIED;
 784 }
 785 
 786 /* change notify request - always async */
 787 static NTSTATUS cvfs_notify(struct ntvfs_module_context *ntvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 788                             struct ntvfs_request *req,
 789                             union smb_notify *io)
 790 {
 791         return NT_STATUS_NOT_IMPLEMENTED;
 792 }
 793 
 794 /*
 795   initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
 796  */
 797 NTSTATUS ntvfs_smb2_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 798 {
 799         NTSTATUS ret;
 800         struct ntvfs_ops ops;
 801         NTVFS_CURRENT_CRITICAL_SIZES(vers);
 802 
 803         ZERO_STRUCT(ops);
 804 
 805         /* fill in the name and type */
 806         ops.name = "smb2";
 807         ops.type = NTVFS_DISK;
 808         
 809         /* fill in all the operations */
 810         ops.connect = cvfs_connect;
 811         ops.disconnect = cvfs_disconnect;
 812         ops.unlink = cvfs_unlink;
 813         ops.chkpath = cvfs_chkpath;
 814         ops.qpathinfo = cvfs_qpathinfo;
 815         ops.setpathinfo = cvfs_setpathinfo;
 816         ops.open = cvfs_open;
 817         ops.mkdir = cvfs_mkdir;
 818         ops.rmdir = cvfs_rmdir;
 819         ops.rename = cvfs_rename;
 820         ops.copy = cvfs_copy;
 821         ops.ioctl = cvfs_ioctl;
 822         ops.read = cvfs_read;
 823         ops.write = cvfs_write;
 824         ops.seek = cvfs_seek;
 825         ops.flush = cvfs_flush; 
 826         ops.close = cvfs_close;
 827         ops.exit = cvfs_exit;
 828         ops.lock = cvfs_lock;
 829         ops.setfileinfo = cvfs_setfileinfo;
 830         ops.qfileinfo = cvfs_qfileinfo;
 831         ops.fsinfo = cvfs_fsinfo;
 832         ops.lpq = cvfs_lpq;
 833         ops.search_first = cvfs_search_first;
 834         ops.search_next = cvfs_search_next;
 835         ops.search_close = cvfs_search_close;
 836         ops.trans = cvfs_trans;
 837         ops.logoff = cvfs_logoff;
 838         ops.async_setup = cvfs_async_setup;
 839         ops.cancel = cvfs_cancel;
 840         ops.notify = cvfs_notify;
 841 
 842         /* register ourselves with the NTVFS subsystem. We register
 843            under the name 'smb2'. */
 844         ret = ntvfs_register(&ops, &vers);
 845 
 846         if (!NT_STATUS_IS_OK(ret)) {
 847                 DEBUG(0,("Failed to register SMB2 backend\n"));
 848         }
 849         
 850         return ret;
 851 }

/* [<][>][^][v][top][bottom][index][help] */