Remove another use of global_loadparm.
[jra/samba/.git] / source4 / ntvfs / ntvfs_generic.c
index aa3009d86ec8824e80923a85fa00880f3f28ff69..554d5c5aef001573a50ccb13580a7c8984d8f700 100644 (file)
@@ -7,7 +7,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -16,8 +16,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 /*
   this implements mappings between info levels for NTVFS backend calls
@@ -117,21 +116,21 @@ static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS statu
   see if a filename ends in EXE COM DLL or SYM. This is needed for the
   DENY_DOS mapping for OpenX
 */
-BOOL is_exe_filename(const char *fname)
+bool is_exe_filename(const char *fname)
 {
        char *p;
        p = strrchr(fname, '.');
        if (!p) {
-               return False;
+               return false;
        }
        p++;
        if (strcasecmp(p, "EXE") == 0 ||
            strcasecmp(p, "COM") == 0 ||
            strcasecmp(p, "DLL") == 0 ||
            strcasecmp(p, "SYM") == 0) {
-               return True;
+               return true;
        }
-       return False;
+       return false;
 }
 
 
@@ -208,8 +207,23 @@ static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
                break;
 
        case RAW_OPEN_SMB2:
+               ZERO_STRUCT(io->smb2.out);
                io->smb2.out.file.ntvfs         = io2->generic.out.file.ntvfs;
-               io->smb2.out.oplock_flags       = 0;
+               switch (io2->generic.out.oplock_level) {
+               case BATCH_OPLOCK_RETURN:
+                       io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+                       break;
+               case EXCLUSIVE_OPLOCK_RETURN:
+                       io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+                       break;
+               case LEVEL_II_OPLOCK_RETURN:
+                       io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
+                       break;
+               default:
+                       io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+                       break;
+               }
+               io->smb2.out.reserved           = 0;
                io->smb2.out.create_action      = io2->generic.out.create_action;
                io->smb2.out.create_time        = io2->generic.out.create_time;
                io->smb2.out.access_time        = io2->generic.out.access_time;
@@ -218,8 +232,8 @@ static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
                io->smb2.out.alloc_size         = io2->generic.out.alloc_size;
                io->smb2.out.size               = io2->generic.out.size;
                io->smb2.out.file_attr          = io2->generic.out.attrib;
-               io->smb2.out._pad               = 0;
-               io->smb2.out.blob               = data_blob(NULL, 0);
+               io->smb2.out.reserved2          = 0;
+               io->smb2.out.maximal_access     = io2->generic.out.maximal_access;
                break;
 
        default:
@@ -362,7 +376,7 @@ static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
 /* 
    NTVFS open generic to any mapper
 */
-_PUBLIC_ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
+NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
                                 struct ntvfs_request *req,
                                 union smb_open *io)
 {
@@ -485,19 +499,50 @@ _PUBLIC_ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
                status = ntvfs->ops->open(ntvfs, req, io2);
                break;
        case RAW_OPEN_SMB2:
-               io2->generic.in.flags           = 0;
+               switch (io->smb2.in.oplock_level) {
+               case SMB2_OPLOCK_LEVEL_BATCH:
+                       io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
+                                               NTCREATEX_FLAGS_REQUEST_OPLOCK;
+                       break;
+               case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
+                       io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
+                       break;
+               default:
+                       io2->generic.in.flags = 0;
+                       break;
+               }
                io2->generic.in.root_fid        = 0;
-               io2->generic.in.access_mask     = io->smb2.in.access_mask;
-               io2->generic.in.alloc_size      = 0;
-               io2->generic.in.file_attr       = io->smb2.in.file_attr;
+               io2->generic.in.access_mask     = io->smb2.in.desired_access;
+               io2->generic.in.alloc_size      = io->smb2.in.alloc_size;
+               io2->generic.in.file_attr       = io->smb2.in.file_attributes;
                io2->generic.in.share_access    = io->smb2.in.share_access;
-               io2->generic.in.open_disposition= io->smb2.in.open_disposition;
+               io2->generic.in.open_disposition= io->smb2.in.create_disposition;
                io2->generic.in.create_options  = io->smb2.in.create_options;
-               io2->generic.in.impersonation   = io->smb2.in.impersonation;
+               io2->generic.in.impersonation   = io->smb2.in.impersonation_level;
                io2->generic.in.security_flags  = 0;
                io2->generic.in.fname           = io->smb2.in.fname;
-               io2->generic.in.sec_desc        = NULL;
-               io2->generic.in.ea_list         = NULL;
+               io2->generic.in.sec_desc        = io->smb2.in.sec_desc;
+               io2->generic.in.ea_list         = &io->smb2.in.eas;
+               io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access; 
+
+               /* we don't support timewarp yet */
+               if (io->smb2.in.timewarp != 0) {
+                       status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                       break;
+               }
+
+               /* we need to check these bits before we check the private mask */
+               if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
+                       DEBUG(2,(__location__ " create_options 0x%x not supported\n",
+                                io2->generic.in.create_options));
+                       status = NT_STATUS_NOT_SUPPORTED;
+                       break;
+               }
+
+               /* TODO: find out why only SMB2 ignores these */
+               io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
+               io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
+
                status = ntvfs->ops->open(ntvfs, req, io2);             
                break;
 
@@ -513,7 +558,7 @@ done:
 /* 
    NTVFS fsinfo generic to any mapper
 */
-_PUBLIC_ NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
+NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
                                   struct ntvfs_request *req,
                                   union smb_fsinfo *fs)
 {
@@ -642,7 +687,7 @@ _PUBLIC_ NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
 /* 
    NTVFS fileinfo generic to any mapper
 */
-_PUBLIC_ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
+NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
                                     union smb_fileinfo *info, 
                                     union smb_fileinfo *info2)
 {
@@ -873,7 +918,7 @@ _PUBLIC_ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
 /* 
    NTVFS fileinfo generic to any mapper
 */
-_PUBLIC_ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
+NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
                                      struct ntvfs_request *req,
                                      union smb_fileinfo *info)
 {
@@ -906,7 +951,7 @@ _PUBLIC_ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
 /* 
    NTVFS pathinfo generic to any mapper
 */
-_PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
+NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
                                      struct ntvfs_request *req,
                                      union smb_fileinfo *info)
 {
@@ -940,9 +985,9 @@ _PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
 /* 
    NTVFS lock generic to any mapper
 */
-_PUBLIC_ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
-                                struct ntvfs_request *req,
-                                union smb_lock *lck)
+NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
+                       struct ntvfs_request *req,
+                       union smb_lock *lck)
 {
        union smb_lock *lck2;
        struct smb_lock_entry *locks;
@@ -987,37 +1032,75 @@ _PUBLIC_ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
                locks->count = lck->unlock.in.count;
                break;
 
-       case RAW_LOCK_SMB2:
-               if (lck->smb2.in.unknown1 != 1) {
+       case RAW_LOCK_SMB2: {
+               /* this is only approximate! We need to change the
+                  generic structure to fix this properly */
+               int i;
+               bool isunlock;
+               if (lck->smb2.in.lock_count < 1) {
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
                lck2->generic.level = RAW_LOCK_GENERIC;
                lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
-               if (lck->smb2.in.flags & SMB2_LOCK_FLAG_EXCLUSIV) {
-                       lck2->generic.in.mode = 0;
-               } else {
-                       lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
+               lck2->generic.in.timeout = UINT32_MAX;
+               lck2->generic.in.mode = 0;
+               lck2->generic.in.lock_cnt = 0;
+               lck2->generic.in.ulock_cnt = 0;
+               lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry, 
+                                                          lck->smb2.in.lock_count);
+               if (lck2->generic.in.locks == NULL) {
+                       return NT_STATUS_NO_MEMORY;
                }
-               if (lck->smb2.in.flags & SMB2_LOCK_FLAG_NO_PENDING) {
-                       lck2->generic.in.timeout = 0;
+               /* only the first lock gives the UNLOCK bit - see
+                  MS-SMB2 3.3.5.14 */
+               if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
+                       lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
+                       isunlock = true;
                } else {
-                       lck2->generic.in.timeout = UINT32_MAX;
+                       lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
+                       isunlock = false;
                }
-               if (lck->smb2.in.flags & SMB2_LOCK_FLAG_UNLOCK) {
-                       lck2->generic.in.ulock_cnt = 1;
-                       lck2->generic.in.lock_cnt = 0;
-               } else {
-                       lck2->generic.in.ulock_cnt = 0;
-                       lck2->generic.in.lock_cnt = 1;
+               for (i=0;i<lck->smb2.in.lock_count;i++) {
+                       if (isunlock && 
+                           (lck->smb2.in.locks[i].flags & 
+                            (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+                       if (!isunlock && 
+                           (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+                       lck2->generic.in.locks[i].pid    = req->smbpid;
+                       lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
+                       lck2->generic.in.locks[i].count  = lck->smb2.in.locks[i].length;
+                       if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
+                               lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
+                       }
+                       if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
+                               lck2->generic.in.timeout = 0;
+                       }
                }
-               lck2->generic.in.locks = locks;
-               locks->pid = 0;
-               locks->offset = lck->smb2.in.offset;
-               locks->count = lck->smb2.in.count;
+               /* initialize output value */
+               lck->smb2.out.reserved = 0;
+               break;
+       }
+
+       case RAW_LOCK_SMB2_BREAK:
+               lck2->generic.level             = RAW_LOCK_GENERIC;
+               lck2->generic.in.file.ntvfs     = lck->smb2_break.in.file.ntvfs;
+               lck2->generic.in.mode           = LOCKING_ANDX_OPLOCK_RELEASE |
+                                                 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
+               lck2->generic.in.timeout        = 0;
+               lck2->generic.in.ulock_cnt      = 0;
+               lck2->generic.in.lock_cnt       = 0;
+               lck2->generic.in.locks          = NULL;
 
                /* initialize output value */
-               lck->smb2.out.unknown1 = 0;
+               lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
+               lck->smb2_break.out.reserved    = lck->smb2_break.in.reserved;
+               lck->smb2_break.out.reserved2   = lck->smb2_break.in.reserved2;
+               lck->smb2_break.out.file        = lck->smb2_break.in.file;
                break;
        }
 
@@ -1115,7 +1198,7 @@ static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
 /* 
    NTVFS write generic to any mapper
 */
-_PUBLIC_ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
+NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
                                  struct ntvfs_request *req,
                                  union smb_write *wr)
 {
@@ -1215,7 +1298,8 @@ static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
                break;
        case RAW_READ_SMB2:
                rd->smb2.out.data.length= rd2->generic.out.nread;
-               rd->smb2.out.unknown1   = 0;
+               rd->smb2.out.remaining  = 0;
+               rd->smb2.out.reserved   = 0;
                break;
        default:
                return NT_STATUS_INVALID_LEVEL;
@@ -1227,7 +1311,7 @@ static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
 /* 
    NTVFS read* to readx mapper
 */
-_PUBLIC_ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
+NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
                                 struct ntvfs_request *req,
                                 union smb_read *rd)
 {
@@ -1248,7 +1332,7 @@ _PUBLIC_ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
        }
 
        rd2->readx.level = RAW_READ_READX;
-       rd2->readx.in.read_for_execute = False;
+       rd2->readx.in.read_for_execute = false;
 
        switch (rd->generic.level) {
        case RAW_READ_READX:
@@ -1307,7 +1391,7 @@ _PUBLIC_ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
        case RAW_READ_SMB2:
                rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
                rd2->readx.in.offset    = rd->smb2.in.offset;
-               rd2->readx.in.mincnt    = rd->smb2.in.length;
+               rd2->readx.in.mincnt    = rd->smb2.in.min_count;
                rd2->readx.in.maxcnt    = rd->smb2.in.length;
                rd2->readx.in.remaining = 0;
                rd2->readx.out.data     = rd->smb2.out.data.data;
@@ -1323,11 +1407,42 @@ done:
 /* 
    NTVFS close generic to any mapper
 */
-_PUBLIC_ NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
+static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
+                                       struct ntvfs_request *req,
+                                       union smb_close *cl, 
+                                       union smb_close *cl2, 
+                                       NTSTATUS status)
+{
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       switch (cl->generic.level) {
+       case RAW_CLOSE_SMB2:
+               cl->smb2.out.flags        = cl2->generic.out.flags;
+               cl->smb2.out._pad         = 0;
+               cl->smb2.out.create_time  = cl2->generic.out.create_time;
+               cl->smb2.out.access_time  = cl2->generic.out.access_time;
+               cl->smb2.out.write_time   = cl2->generic.out.write_time;
+               cl->smb2.out.change_time  = cl2->generic.out.change_time;
+               cl->smb2.out.alloc_size   = cl2->generic.out.alloc_size;
+               cl->smb2.out.size         = cl2->generic.out.size;
+               cl->smb2.out.file_attr    = cl2->generic.out.file_attr;
+               break;
+       default:
+               break;
+       }
+
+       return status;
+}
+
+/* 
+   NTVFS close generic to any mapper
+*/
+NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
                                  struct ntvfs_request *req,
                                  union smb_close *cl)
 {
        union smb_close *cl2;
+       NTSTATUS status;
 
        cl2 = talloc(req, union smb_close);
        if (cl2 == NULL) {
@@ -1335,30 +1450,38 @@ _PUBLIC_ NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
        }
 
        switch (cl->generic.level) {
-       case RAW_CLOSE_CLOSE:
+       case RAW_CLOSE_GENERIC:
                return NT_STATUS_INVALID_LEVEL;
 
+       case RAW_CLOSE_CLOSE:
+               cl2->generic.level              = RAW_CLOSE_GENERIC;
+               cl2->generic.in.file            = cl->close.in.file;
+               cl2->generic.in.write_time      = cl->close.in.write_time;
+               cl2->generic.in.flags           = 0;
+               break;
+
        case RAW_CLOSE_SPLCLOSE:
-               cl2->generic.level              = RAW_CLOSE_CLOSE;
-               cl2->generic.in.file.ntvfs      = cl->splclose.in.file.ntvfs;
+               cl2->generic.level              = RAW_CLOSE_GENERIC;
+               cl2->generic.in.file            = cl->splclose.in.file;
                cl2->generic.in.write_time      = 0;
+               cl2->generic.in.flags           = 0;
                break;
 
        case RAW_CLOSE_SMB2:
-               cl2->generic.level              = RAW_CLOSE_CLOSE;
-               cl2->generic.in.file.ntvfs      = cl->smb2.in.file.ntvfs;
+               cl2->generic.level              = RAW_CLOSE_GENERIC;
+               cl2->generic.in.file            = cl->smb2.in.file;
                cl2->generic.in.write_time      = 0;
-               /* SMB2 Close has output parameter, but we just zero them */
-               ZERO_STRUCT(cl->smb2.out);
+               cl2->generic.in.flags           = cl->smb2.in.flags;
                break;
        }
 
-       /* 
-        * we don't need to call ntvfs_map_async_setup() here,
-        * as close() doesn't have any output fields
-        */
+       status = ntvfs_map_async_setup(ntvfs, req, cl, cl2, 
+                                      (second_stage_t)ntvfs_map_close_finish);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       status = ntvfs->ops->close(ntvfs, req, cl2);
 
-       return ntvfs->ops->close(ntvfs, req, cl2);
+       return ntvfs_map_async_finish(req, status);
 }
 
 /* 
@@ -1392,7 +1515,7 @@ static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
 /* 
    NTVFS notify generic to any mapper
 */
-_PUBLIC_ NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
+NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
                                   struct ntvfs_request *req,
                                   union smb_notify *nt)
 {