WIP: Richard's POSIX patch
authorRichard Sharpe <rsharpe@samba.org>
Sat, 26 Sep 2015 14:19:57 +0000 (16:19 +0200)
committerRalph Boehme <slow@samba.org>
Sun, 22 Nov 2015 13:44:03 +0000 (14:44 +0100)
libcli/smb/smb2_constants.h
source3/smbd/filename.c
source3/smbd/smb2_create.c
source3/smbd/smb2_getinfo.c
source3/torture/proto.h
source3/torture/test_smb2.c
source3/torture/torture.c
source4/torture/smb2/smb2.c
source4/torture/smb2/wscript_build

index f6edf6ba109d9fa5d8591901e6bfd978581e2509..808762a8506e05992e739fb38f735f24a01aa25a 100644 (file)
 #define SMB2_CREATE_TAG_APP_INSTANCE_ID "\x45\xBC\xA6\x6A\xEF\xA7\xF7\x4A\x90\x08\xFA\x46\x2E\x14\x4D\x74"
 #define SVHDX_OPEN_DEVICE_CONTEXT "\x9C\xCB\xCF\x9E\x04\xC1\xE6\x43\x98\x0E\x15\x8D\xA1\xF6\xEC\x83"
 
+/*
+ * Experimental POSIX CREATE CONTEXTS ...
+ */
+#define SMB2_POSIX_V1_CAPS "\x01\x35\x26\x34\x21\x29\x12\x49\x25\x86\x44\x77\x94\x11\x45\x31"
+#define SMB2_POSIX_V1_STAT_INFO "\x77\x11\x30\x82\x23\x13\x84\x39\x27\x12\x84\x76\x64\x82\x72\x54"
+
+/*
+ * Constants for the POSIX contexts
+ */
+#define POSIX_V1_POSIX_LOCK            0x00000001
+#define POSIX_V1_POSIX_FILE_SEMANTICS  0x00000008
+#define POSIX_V1_CASE_SENSITIVE                0x00000010
+#define POSIX_V1_POSIX_STAT_INFO       0x00000040
+
+/*
+ * Structures associated with POSIX contexts. These should go somewhere else.
+ */
+struct posix_v1_request {
+       uint32_t version;
+       uint32_t may_have_flags;
+       uint32_t must_have_flags;
+       uint32_t reserved;
+} __attribute__((packed));
+
+struct posix_v1_response {
+       uint32_t version;
+       uint32_t granted_flags;
+       uint32_t must_have_flags;
+       uint32_t reserved;
+} __attribute__((packed));
+
+struct posix_v1_query_inode_info_response {
+       uint64_t uid;
+       uint64_t gid;
+       uint64_t type;
+       uint64_t dev_major;
+       uint64_t dev_minor;
+       uint64_t unique_id;
+       uint64_t permissions;
+       uint64_t nlinks;
+} __attribute__((packed));
+
 /* SMB2 notify flags */
 #define SMB2_WATCH_TREE 0x0001
 
 #define SMB2_GETINFO_FS                 0x02
 #define SMB2_GETINFO_SECURITY           0x03
 #define SMB2_GETINFO_QUOTA              0x04
+#define SMB2_GETINFO_UNIX              0x10
 
 #define SMB2_CLOSE_FLAGS_FULL_INFORMATION (0x01)
 
index 555658de0149a9d19f9b77022d447ad8f97cd48d..a2d44b226f1f758953a9eef79cb48d3dbc99a8ac 100644 (file)
@@ -500,7 +500,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
                 * won't help.
                 */
 
-               if ((conn->case_sensitive || !(conn->fs_capabilities &
+               if ((conn->case_sensitive ||
+                                       (ucf_flags & UCF_UNIX_NAME_LOOKUP) ||
+                                       !(conn->fs_capabilities &
                                        FILE_CASE_SENSITIVE_SEARCH)) &&
                                !mangle_is_mangled(smb_fname->base_name, conn->params)) {
 
index 1b12962f4575faa279ff84fd443792ba7a053a56..e73fe75a37d0373cc1317af2ff652b701ebbf1d4 100644 (file)
@@ -1004,6 +1004,20 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                        info = FILE_WAS_OPENED;
                } else {
                        struct smb_filename *smb_fname = NULL;
+                       struct smb2_create_blob *posix = NULL;
+                       uint32_t ucf_flags = UCF_PREP_CREATEFILE;
+
+                       /*
+                        * If we have the new POSIX CREATE, add the flag
+                        * to get filename_convert to do what we need.
+                        *
+                        * TODO: We should validate the flags as well.
+                        */
+                       posix = smb2_create_blob_find(&in_context_blobs,
+                                                     SMB2_POSIX_V1_CAPS);
+
+                       if (posix)
+                               ucf_flags |= UCF_UNIX_NAME_LOOKUP;
 
                        if (requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
                                if (lease_ptr == NULL) {
@@ -1031,7 +1045,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                                  smb1req->conn,
                                                  smb1req->flags2 & FLAGS2_DFS_PATHNAMES,
                                                  fname,
-                                                 UCF_PREP_CREATEFILE,
+                                                 ucf_flags,
                                                  NULL, /* ppath_contains_wcards */
                                                  &smb_fname);
                        if (!NT_STATUS_IS_OK(status)) {
@@ -1101,6 +1115,61 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                return tevent_req_post(req, ev);
                        }
                        op = result->op;
+
+                       /*
+                        * Now push on the POSIX blobs needed
+                        */
+                       if (posix) {
+                               struct posix_v1_request *p_req = NULL;
+                               struct posix_v1_response p_resp;
+                               struct posix_v1_query_inode_info_response p;
+                               DATA_BLOB rblob = data_blob_const((const void *)&p_resp, sizeof(p_resp));
+                               DATA_BLOB blob = data_blob_const((const void *)&p, sizeof(p));
+
+                               p_req = (struct posix_v1_request *)posix->data.data;
+
+                               p_resp.version = 1;
+                               p_resp.granted_flags = p_req->must_have_flags;
+                               p_resp.must_have_flags = p_req->must_have_flags;
+                               p_resp.reserved = 0;
+
+                               status = smb2_create_blob_add(
+                                       state->out_context_blobs,
+                                       state->out_context_blobs,
+                                       SMB2_POSIX_V1_CAPS,
+                                       rblob);
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       tevent_req_nterror(req, status);
+                                       return tevent_req_post(req, ev);
+                               }
+
+                               /*
+                                * Now add the stat info if asked for
+                                */
+                               if (p_req->must_have_flags & POSIX_V1_POSIX_STAT_INFO) {
+                                       SMB_STRUCT_STAT *st = &result->fsp_name->st;
+
+                                       p.uid = st->st_ex_uid;
+                                       p.gid = st->st_ex_gid;
+                                       p.type = st->st_ex_mode & 0770000;
+                                       p.dev_major = major(st->st_ex_dev);
+                                       p.dev_minor = minor(st->st_ex_dev);
+                                       p.unique_id = get_FileIndex(
+                                                       result->conn, st);
+                                       p.permissions = st->st_ex_mode & S_IFMT;
+                                       p.nlinks = st->st_ex_nlink;
+
+                                       status = smb2_create_blob_add(
+                                               state->out_context_blobs,
+                                               state->out_context_blobs,
+                                               SMB2_POSIX_V1_STAT_INFO,
+                                               blob);
+                                       if (!NT_STATUS_IS_OK(status)) {
+                                               tevent_req_nterror(req, status);
+                                               return tevent_req_post(req, ev);
+                                       }
+                               }
+                       }
                }
 
                /*
index 7f44868bade163e302910134d3f326a0df8ae949..db12b2482f76b411c29164b5f4fc482d0b029a89 100644 (file)
@@ -417,6 +417,68 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
                break;
        }
 
+       /*
+        * Map these to the old POSIX stuff ...
+        */
+       case SMB2_GETINFO_UNIX:
+       {
+               uint16_t file_info_level = 0x200 | in_file_info_class;
+               char *data = NULL;
+               unsigned int data_size = 0;
+               bool delete_pending = false;
+               struct timespec write_time_ts;
+               struct file_id fileid;
+               struct ea_list *ea_list = NULL;
+               int lock_data_count = 0;
+               char *lock_data = NULL;
+               size_t fixed_portion;
+
+               status = smbd_do_qfilepathinfo(conn, state,
+                                              file_info_level,
+                                              fsp,
+                                              fsp->fsp_name,
+                                              delete_pending,
+                                              write_time_ts,
+                                              ea_list,
+                                              lock_data_count,
+                                              lock_data,
+                                              STR_UNICODE,
+                                              in_output_buffer_length,
+                                              &fixed_portion,
+                                              &data,
+                                              &data_size);
+               if (!NT_STATUS_IS_OK(status)) {
+                       SAFE_FREE(data);
+                       if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) {
+                               status = NT_STATUS_INVALID_INFO_CLASS;
+                       }
+                       tevent_req_nterror(req, status);
+                       return tevent_req_post(req, ev);
+               }
+               if (in_output_buffer_length < fixed_portion) {
+                       SAFE_FREE(data);
+                       tevent_req_nterror(
+                               req, NT_STATUS_INFO_LENGTH_MISMATCH);
+                       return tevent_req_post(req, ev);
+               }
+               if (data_size > 0) {
+                       state->out_output_buffer = data_blob_talloc(state,
+                                                                   data,
+                                                                   data_size);
+                       SAFE_FREE(data);
+                       if (tevent_req_nomem(state->out_output_buffer.data, req)) {
+                               return tevent_req_post(req, ev);
+                       }
+                       if (data_size > in_output_buffer_length) {
+                               state->out_output_buffer.length =
+                                       in_output_buffer_length;
+                               status = STATUS_BUFFER_OVERFLOW;
+                       }
+               }
+               SAFE_FREE(data);
+               break;
+       }
+
        case SMB2_GETINFO_FS:
        {
                uint16_t file_info_level;
index fc7c33f2d231ebcdd2865d6c75d571000834539e..8ca87b3c5caf3211eac28478800b3bd566feef7f 100644 (file)
@@ -92,6 +92,7 @@ bool run_addrchange(int dummy);
 bool run_notify_online(int dummy);
 bool run_nttrans_create(int dummy);
 bool run_nttrans_fsctl(int dummy);
+bool run_smb2_posix_create(int dummy);
 bool run_smb2_basic(int dummy);
 bool run_smb2_negprot(int dummy);
 bool run_smb2_session_reconnect(int dummy);
index 6871f4c22721d1243eaa168852a184637bfd5857..c398a6ce623b695a8362287ac8e73acb47590d64 100644 (file)
 
 extern fstring host, workgroup, share, password, username, myname;
 
+bool run_smb2_posix_create(int dummy)
+{
+       struct cli_state *cli;
+       NTSTATUS status;
+       uint64_t fid_persistent, fid_volatile;
+       const char *hello = "Hello, world\n";
+       uint8_t *result;
+       uint32_t nread;
+       uint8_t *dir_data;
+       uint32_t dir_data_length;
+       uint32_t saved_tid = 0;
+       struct smbXcli_tcon *saved_tcon = NULL;
+       uint64_t saved_uid = 0;
+       struct smb2_create_blobs *create_blobs = NULL, *ret_blobs = NULL;
+       struct posix_v1_request posix_create_context;
+       DATA_BLOB posix_create_blob =
+               data_blob_const((const void *)&posix_create_context,
+                               sizeof(posix_create_context));
+
+       printf("Starting SMB2-POSIX-CREATE\n");
+
+       if (!torture_init_connection(&cli)) {
+               return false;
+       }
+
+       status = smbXcli_negprot(cli->conn, cli->timeout,
+                                PROTOCOL_SMB2_02, PROTOCOL_SMB2_02);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("smbXcli_negprot returned %s\n", nt_errstr(status));
+               return false;
+       }
+
+       status = cli_session_setup(cli, username,
+                                  password, strlen(password),
+                                  password, strlen(password),
+                                  workgroup);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_session_setup returned %s\n", nt_errstr(status));
+               return false;
+       }
+
+       status = cli_tree_connect(cli, share, "?????", "", 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("cli_tree_connect returned %s\n", nt_errstr(status));
+               return false;
+       }
+
+       create_blobs = talloc_zero(cli, struct smb2_create_blobs);
+       if (!create_blobs) {
+               printf("allocation of create blobs failed\n");
+               return false;
+       }
+
+       ret_blobs = talloc_zero(cli, struct smb2_create_blobs);
+       if (!ret_blobs) {
+               printf("allocation of ret blobs failed\n");
+               return false;
+       }
+
+       /* The blob is set up above, modify the struct */
+       posix_create_context.version = 1;
+       posix_create_context.may_have_flags = 0;
+       posix_create_context.must_have_flags = POSIX_V1_CASE_SENSITIVE | 
+                                               POSIX_V1_POSIX_STAT_INFO;
+       posix_create_context.reserved = 0;
+
+       status = smb2_create_blob_add(create_blobs,
+                                     create_blobs,
+                                     SMB2_POSIX_V1_CAPS,
+                                     posix_create_blob);
+
+       status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
+                       cli->smb2.tcon, "smb2-basic.txt",
+                       SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
+                       SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
+                       SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
+                       FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
+                       FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
+                       FILE_CREATE, /* create_disposition, */
+                       0, /* create_options, */
+                       create_blobs, /* smb2_create_blobs *blobs */
+                       &fid_persistent,
+                       &fid_volatile,
+                       NULL, NULL, ret_blobs);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("smb2cli_create returned %s\n", nt_errstr(status));
+               return false;
+       }
+
+       status = smb2cli_close(cli->conn, cli->timeout, cli->smb2.session,
+                              cli->smb2.tcon, 0, fid_persistent, fid_volatile);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("smb2cli_close returned %s\n", nt_errstr(status));
+               return false;
+       }
+
+       printf("Created smb2-basic.txt\n");
+
+       /* Create another file with slight difference in name */
+       status = smb2cli_create(cli->conn, cli->timeout, cli->smb2.session,
+                       cli->smb2.tcon, "Smb2-Basic.txt",
+                       SMB2_OPLOCK_LEVEL_NONE, /* oplock_level, */
+                       SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level, */
+                       SEC_STD_ALL | SEC_FILE_ALL, /* desired_access, */
+                       FILE_ATTRIBUTE_NORMAL, /* file_attributes, */
+                       FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access, */
+                       FILE_CREATE, /* create_disposition, */
+                       0, /* create_options, */
+                       create_blobs, /* smb2_create_blobs *blobs */
+                       &fid_persistent,
+                       &fid_volatile,
+                       NULL, NULL, NULL);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("smb2cli_create returned %s\n", nt_errstr(status));
+               return false;
+       }
+
+       status = smb2cli_close(cli->conn, cli->timeout, cli->smb2.session,
+                              cli->smb2.tcon, 0, fid_persistent, fid_volatile);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("smb2cli_close returned %s\n", nt_errstr(status));
+               return false;
+       }
+
+       printf("Created Smb2-Basic.txt\n");
+
+       status = smb2cli_query_directory(
+               cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
+               1, 0, 0, fid_persistent, fid_volatile, "*", 0xffff,
+               talloc_tos(), &dir_data, &dir_data_length);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("smb2cli_query_directory returned %s\n", nt_errstr(status));
+               return false;
+       }
+
+       status = smb2cli_tdis(cli->conn,
+                             cli->timeout,
+                             cli->smb2.session,
+                             cli->smb2.tcon);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) {
+               printf("2nd smb2cli_tdis returned %s\n", nt_errstr(status));
+               return false;
+       }
+
+       return true;
+}
+
 bool run_smb2_basic(int dummy)
 {
        struct cli_state *cli;
index ef75d2140c4caec235cb83069806d674cb0ff549..46cda243ae9d7937f1ecf46a9bd0291116d35394 100644 (file)
@@ -9649,6 +9649,7 @@ static struct {
        { "BAD-NBT-SESSION", run_bad_nbt_session },
        { "SMB-ANY-CONNECT", run_smb_any_connect },
        { "NOTIFY-ONLINE", run_notify_online },
+       { "SMB2-POSIX-CREATE", run_smb2_posix_create },
        { "SMB2-BASIC", run_smb2_basic },
        { "SMB2-NEGPROT", run_smb2_negprot },
        { "SMB2-SESSION-RECONNECT", run_smb2_session_reconnect },
index 0124cf1252b3ebb9d9635dca2124177151f6c8e5..b54862728d0261f2e96ff0af9b7cbe1873c33a32 100644 (file)
@@ -173,6 +173,8 @@ NTSTATUS torture_smb2_init(void)
 
        torture_suite_add_suite(suite, torture_smb2_doc_init());
 
+       torture_suite_add_suite(suite, torture_smb2_posix_init());
+
        suite->description = talloc_strdup(suite, "SMB2-specific tests");
 
        torture_register_suite(suite);
index 1c593efcc76278133b9d5dbf525da04d210f1d19..c4627aa828b75765c47cc8708d21d978a3f04524 100644 (file)
@@ -4,7 +4,7 @@ bld.SAMBA_MODULE('TORTURE_SMB2',
        source='''connect.c scan.c util.c getinfo.c setinfo.c lock.c notify.c
        smb2.c durable_open.c durable_v2_open.c oplock.c dir.c lease.c create.c
        acls.c read.c compound.c streams.c ioctl.c rename.c
-       session.c delete-on-close.c replay.c notify_disabled.c''',
+       session.c delete-on-close.c replay.c notify_disabled.c posix.c''',
        subsystem='smbtorture',
        deps='LIBCLI_SMB2 POPT_CREDENTIALS torture NDR_IOCTL',
        internal_module=True,