Fixed SMB2 rename operations from Vista clients
authorAndrew Tridgell <tridge@samba.org>
Thu, 14 Feb 2008 01:30:31 +0000 (12:30 +1100)
committerAndrew Tridgell <tridge@samba.org>
Thu, 14 Feb 2008 01:30:31 +0000 (12:30 +1100)
We needed a flag in bufinfo to mark packets as SMB2, as it seems that
SMB2 uses a different format for the RenameInformation buffer than SMB
does

Also handle the fact that SMB2 clients give the full path to the
target file in the rename, not a relative path
(This used to be commit 52d7972d95ddc19d22a4187b4d4428a6c3ed32d5)

source4/libcli/raw/interfaces.h
source4/libcli/raw/rawrequest.c
source4/libcli/raw/request.h
source4/libcli/smb2/request.c
source4/ntvfs/posix/pvfs_setfileinfo.c
source4/smb_server/blob.c
source4/smb_server/smb/request.c
source4/smb_server/smb2/receive.c

index ce6323f2e53040dd948e6702e72f61a709f105dd..16db17d7abc36fc2f20e9bd2da107933edcb7719 100644 (file)
@@ -1000,7 +1000,7 @@ union smb_setfileinfo {
                struct {
                        union smb_handle_or_path file;
                        uint8_t overwrite;
-                       uint32_t root_fid;
+                       uint64_t root_fid;
                        const char *new_name;
                } in;
        } rename_information;
index dd60cc7f621f30e96c113840601279efb1629b52..355d092583bf869b092bb56ca35b1e75d1773cb1 100644 (file)
 void smb_setup_bufinfo(struct smbcli_request *req)
 {
        req->in.bufinfo.mem_ctx    = req;
-       req->in.bufinfo.unicode    = (req->flags2 & FLAGS2_UNICODE_STRINGS)?true:false;
+       req->in.bufinfo.flags      = 0;
+       if (req->flags2 & FLAGS2_UNICODE_STRINGS) {
+               req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE;
+       }
        req->in.bufinfo.align_base = req->in.buffer;
        req->in.bufinfo.data       = req->in.data;
        req->in.bufinfo.data_size  = req->in.data_size;
@@ -658,7 +661,7 @@ size_t smbcli_req_pull_string(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_c
                           char **dest, const uint8_t *src, int byte_len, uint_t flags)
 {
        if (!(flags & STR_ASCII) && 
-           (((flags & STR_UNICODE) || bufinfo->unicode))) {
+           (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
                return smbcli_req_pull_ucs2(bufinfo, mem_ctx, dest, src, byte_len, flags);
        }
 
index 6776d3c349b51fd89acbea3a3afe85f9d37ccc9f..2a572e58eeff050b3d002a91b0cfecc3b774b1ae 100644 (file)
 
 #include "libcli/raw/signing.h"
 
+#define BUFINFO_FLAG_UNICODE 0x0001
+#define BUFINFO_FLAG_SMB2    0x0002
+
 /*
   buffer limit structure used by both SMB and SMB2
  */
 struct request_bufinfo {
        TALLOC_CTX *mem_ctx;
-       bool unicode;
+       uint32_t flags;
        const uint8_t *align_base;
        const uint8_t *data;
        size_t data_size;       
index 0b680fb1669d644b854744b9ea2c0c5e089ee66a..35229dc45f2af419a3b05460b577cacd95afed41 100644 (file)
@@ -32,7 +32,7 @@
 void smb2_setup_bufinfo(struct smb2_request *req)
 {
        req->in.bufinfo.mem_ctx    = req;
-       req->in.bufinfo.unicode    = true;
+       req->in.bufinfo.flags      = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2;
        req->in.bufinfo.align_base = req->in.buffer;
        if (req->in.dynamic) {
                req->in.bufinfo.data       = req->in.dynamic;
index 340913cd4dd0a578c099e1b7de27bfa28f9d7a2f..2a936ad8a716962aa3b1086d93ce4202da0241f5 100644 (file)
@@ -63,6 +63,10 @@ static uint32_t pvfs_setfileinfo_access(union smb_setfileinfo *info)
                }
                break;
 
+       case RAW_SFILEINFO_RENAME_INFORMATION:
+               needed = SEC_STD_DELETE;
+               break;
+
        default:
                needed = SEC_FILE_WRITE_ATTRIBUTE;
                break;
@@ -84,7 +88,8 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
        char *new_name, *p;
 
        /* renames are only allowed within a directory */
-       if (strchr_m(info->rename_information.in.new_name, '\\')) {
+       if (strchr_m(info->rename_information.in.new_name, '\\') &&
+           (req->ctx->protocol != PROTOCOL_SMB2)) {
                return NT_STATUS_NOT_SUPPORTED;
        }
 
@@ -100,22 +105,28 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
 
        /* w2k3 does not appear to allow relative rename */
        if (info->rename_information.in.root_fid != 0) {
-               return NT_STATUS_INVALID_PARAMETER;
+               DEBUG(1,("WARNING: got invalid root_fid in rename_information.\n"));
        }
 
        /* construct the fully qualified windows name for the new file name */
-       new_name = talloc_strdup(req, name->original_name);
-       if (new_name == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       p = strrchr_m(new_name, '\\');
-       if (p == NULL) {
-               return NT_STATUS_OBJECT_NAME_INVALID;
-       }
-       *p = 0;
+       if (req->ctx->protocol == PROTOCOL_SMB2) {
+               /* SMB2 sends the full path of the new name */
+               new_name = talloc_asprintf(req, "\\%s", info->rename_information.in.new_name);
+       } else {
+               new_name = talloc_strdup(req, name->original_name);
+               if (new_name == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               p = strrchr_m(new_name, '\\');
+               if (p == NULL) {
+                       return NT_STATUS_OBJECT_NAME_INVALID;
+               } else {
+                       *p = 0;
+               }
 
-       new_name = talloc_asprintf(req, "%s\\%s", new_name,
-                                  info->rename_information.in.new_name);
+               new_name = talloc_asprintf(req, "%s\\%s", new_name,
+                                          info->rename_information.in.new_name);
+       }
        if (new_name == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
index caf6fb447d218c05fdbc55862b8fe1236972b071..795e7ce5856046143751c1f5fed9140a3eb18969 100644 (file)
@@ -523,7 +523,7 @@ NTSTATUS smbsrv_pull_passthru_sfileinfo(TALLOC_CTX *mem_ctx,
                                        int default_str_flags,
                                        struct request_bufinfo *bufinfo)
 {
-       uint32_t len;
+       uint32_t len, ofs;
        DATA_BLOB str_blob;
 
        switch (level) {
@@ -563,14 +563,23 @@ NTSTATUS smbsrv_pull_passthru_sfileinfo(TALLOC_CTX *mem_ctx,
                if (!bufinfo) {
                        return NT_STATUS_INTERNAL_ERROR;
                }
-               BLOB_CHECK_MIN_SIZE(blob, 12);
-
-               st->rename_information.in.overwrite = CVAL(blob->data, 0);
-               st->rename_information.in.root_fid  = IVAL(blob->data, 4);
-               len                                 = IVAL(blob->data, 8);
-               str_blob.data = blob->data+12;
-               str_blob.length = MIN(blob->length, len);
-               smbsrv_blob_pull_string(bufinfo, &str_blob, 0,
+               if (bufinfo->flags & BUFINFO_FLAG_SMB2) {
+                       /* SMB2 uses a different format for rename information */
+                       BLOB_CHECK_MIN_SIZE(blob, 20);
+                       st->rename_information.in.overwrite = CVAL(blob->data, 0);
+                       st->rename_information.in.root_fid  = BVAL(blob->data, 4);
+                       len                                 = IVAL(blob->data,16);
+                       ofs                                 = 20;                       
+               } else {
+                       BLOB_CHECK_MIN_SIZE(blob, 12);
+                       st->rename_information.in.overwrite = CVAL(blob->data, 0);
+                       st->rename_information.in.root_fid  = IVAL(blob->data, 4);
+                       len                                 = IVAL(blob->data, 8);
+                       ofs                                 = 12;
+               }
+               str_blob = *blob;
+               str_blob.length = MIN(str_blob.length, ofs+len);
+               smbsrv_blob_pull_string(bufinfo, &str_blob, ofs,
                                        &st->rename_information.in.new_name,
                                        STR_UNICODE);
                if (st->rename_information.in.new_name == NULL) {
index 724055499b36096c4d3437387718dfcb229580e7..d7f3793f23dd8603f06d599d0a86eee114393a17 100644 (file)
 void smbsrv_setup_bufinfo(struct smbsrv_request *req)
 {
        req->in.bufinfo.mem_ctx    = req;
-       req->in.bufinfo.unicode    = (req->flags2 & FLAGS2_UNICODE_STRINGS)?true:false;
+       req->in.bufinfo.flags      = 0;
+       if (req->flags2 & FLAGS2_UNICODE_STRINGS) {
+               req->in.bufinfo.flags |= BUFINFO_FLAG_UNICODE;
+       }
        req->in.bufinfo.align_base = req->in.buffer;
        req->in.bufinfo.data       = req->in.data;
        req->in.bufinfo.data_size  = req->in.data_size;
@@ -582,7 +585,7 @@ static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest,
 size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags)
 {
        if (!(flags & STR_ASCII) && 
-           (((flags & STR_UNICODE) || bufinfo->unicode))) {
+           (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
                return req_pull_ucs2(bufinfo, dest, src, byte_len, flags);
        }
 
index 58070065fcaaaf52e75ef72991dcc2581d9b6559..dea7c9e79ea25ae3d7ee049969c7e5bc9db84bc9 100644 (file)
@@ -35,7 +35,7 @@
 void smb2srv_setup_bufinfo(struct smb2srv_request *req)
 {
        req->in.bufinfo.mem_ctx    = req;
-       req->in.bufinfo.unicode    = true;
+       req->in.bufinfo.flags      = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2;
        req->in.bufinfo.align_base = req->in.buffer;
        if (req->in.dynamic) {
                req->in.bufinfo.data       = req->in.dynamic;