s3-net: display full value of "msDS-SupportedEncryptionTypes".
[sfrench/samba-autobuild/.git] / source3 / libsmb / clifile.c
index 3c799a68a334748b461789638c8de7834d159653..61cb8b598930152d9c5fdd8e92c7a5cf94ef6652 100644 (file)
@@ -1792,32 +1792,35 @@ NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
        return status;
 }
 
-struct cli_ntcreate_state {
+struct cli_ntcreate1_state {
        uint16_t vwv[24];
        uint16_t fnum;
+       struct smb_create_returns cr;
+       struct tevent_req *subreq;
 };
 
-static void cli_ntcreate_done(struct tevent_req *subreq);
+static void cli_ntcreate1_done(struct tevent_req *subreq);
+static bool cli_ntcreate1_cancel(struct tevent_req *req);
 
-struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
-                                    struct tevent_context *ev,
-                                    struct cli_state *cli,
-                                    const char *fname,
-                                    uint32_t CreatFlags,
-                                    uint32_t DesiredAccess,
-                                    uint32_t FileAttributes,
-                                    uint32_t ShareAccess,
-                                    uint32_t CreateDisposition,
-                                    uint32_t CreateOptions,
-                                    uint8_t SecurityFlags)
+static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct cli_state *cli,
+                                            const char *fname,
+                                            uint32_t CreatFlags,
+                                            uint32_t DesiredAccess,
+                                            uint32_t FileAttributes,
+                                            uint32_t ShareAccess,
+                                            uint32_t CreateDisposition,
+                                            uint32_t CreateOptions,
+                                            uint8_t SecurityFlags)
 {
        struct tevent_req *req, *subreq;
-       struct cli_ntcreate_state *state;
+       struct cli_ntcreate1_state *state;
        uint16_t *vwv;
        uint8_t *bytes;
        size_t converted_len;
 
-       req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
+       req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
        if (req == NULL) {
                return NULL;
        }
@@ -1864,33 +1867,156 @@ struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
-       tevent_req_set_callback(subreq, cli_ntcreate_done, req);
+       tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
+
+       state->subreq = subreq;
+       tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
+
        return req;
 }
 
-static void cli_ntcreate_done(struct tevent_req *subreq)
+static void cli_ntcreate1_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
-       struct cli_ntcreate_state *state = tevent_req_data(
-               req, struct cli_ntcreate_state);
+       struct cli_ntcreate1_state *state = tevent_req_data(
+               req, struct cli_ntcreate1_state);
        uint8_t wct;
        uint16_t *vwv;
        uint32_t num_bytes;
        uint8_t *bytes;
        NTSTATUS status;
 
-       status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv,
+       status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
                              &num_bytes, &bytes);
        TALLOC_FREE(subreq);
        if (tevent_req_nterror(req, status)) {
                return;
        }
+       state->cr.oplock_level = CVAL(vwv+2, 0);
        state->fnum = SVAL(vwv+2, 1);
+       state->cr.create_action = IVAL(vwv+3, 1);
+       state->cr.creation_time = BVAL(vwv+5, 1);
+       state->cr.last_access_time = BVAL(vwv+9, 1);
+       state->cr.last_write_time = BVAL(vwv+13, 1);
+       state->cr.change_time   = BVAL(vwv+17, 1);
+       state->cr.file_attributes = IVAL(vwv+21, 1);
+       state->cr.allocation_size = BVAL(vwv+23, 1);
+       state->cr.end_of_file   = BVAL(vwv+27, 1);
+
+       tevent_req_done(req);
+}
+
+static bool cli_ntcreate1_cancel(struct tevent_req *req)
+{
+       struct cli_ntcreate1_state *state = tevent_req_data(
+               req, struct cli_ntcreate1_state);
+       return tevent_req_cancel(state->subreq);
+}
+
+static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
+                                  uint16_t *pfnum,
+                                  struct smb_create_returns *cr)
+{
+       struct cli_ntcreate1_state *state = tevent_req_data(
+               req, struct cli_ntcreate1_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       *pfnum = state->fnum;
+       if (cr != NULL) {
+               *cr = state->cr;
+       }
+       return NT_STATUS_OK;
+}
+
+struct cli_ntcreate_state {
+       NTSTATUS (*recv)(struct tevent_req *req, uint16_t *fnum,
+                        struct smb_create_returns *cr);
+       struct smb_create_returns cr;
+       uint16_t fnum;
+       struct tevent_req *subreq;
+};
+
+static void cli_ntcreate_done(struct tevent_req *subreq);
+static bool cli_ntcreate_cancel(struct tevent_req *req);
+
+struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
+                                    struct tevent_context *ev,
+                                    struct cli_state *cli,
+                                    const char *fname,
+                                    uint32_t create_flags,
+                                    uint32_t desired_access,
+                                    uint32_t file_attributes,
+                                    uint32_t share_access,
+                                    uint32_t create_disposition,
+                                    uint32_t create_options,
+                                    uint8_t security_flags)
+{
+       struct tevent_req *req, *subreq;
+       struct cli_ntcreate_state *state;
+
+       req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               state->recv = cli_smb2_create_fnum_recv;
+
+               if (cli->use_oplocks) {
+                       create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
+               }
+
+               subreq = cli_smb2_create_fnum_send(
+                       state, ev, cli, fname, create_flags, desired_access,
+                       file_attributes, share_access, create_disposition,
+                       create_options);
+       } else {
+               state->recv = cli_ntcreate1_recv;
+               subreq = cli_ntcreate1_send(
+                       state, ev, cli, fname, create_flags, desired_access,
+                       file_attributes, share_access, create_disposition,
+                       create_options, security_flags);
+       }
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, cli_ntcreate_done, req);
+
+       state->subreq = subreq;
+       tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
+
+       return req;
+}
+
+static void cli_ntcreate_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_ntcreate_state *state = tevent_req_data(
+               req, struct cli_ntcreate_state);
+       NTSTATUS status;
+
+       status = state->recv(subreq, &state->fnum, &state->cr);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
        tevent_req_done(req);
 }
 
-NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
+static bool cli_ntcreate_cancel(struct tevent_req *req)
+{
+       struct cli_ntcreate_state *state = tevent_req_data(
+               req, struct cli_ntcreate_state);
+       return tevent_req_cancel(state->subreq);
+}
+
+NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
+                          struct smb_create_returns *cr)
 {
        struct cli_ntcreate_state *state = tevent_req_data(
                req, struct cli_ntcreate_state);
@@ -1899,7 +2025,12 @@ NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
        if (tevent_req_is_nterror(req, &status)) {
                return status;
        }
-       *pfnum = state->fnum;
+       if (fnum != NULL) {
+               *fnum = state->fnum;
+       }
+       if (cr != NULL) {
+               *cr = state->cr;
+       }
        return NT_STATUS_OK;
 }
 
@@ -1912,27 +2043,13 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
                      uint32_t CreateDisposition,
                      uint32_t CreateOptions,
                      uint8_t SecurityFlags,
-                     uint16_t *pfid)
+                     uint16_t *pfid,
+                     struct smb_create_returns *cr)
 {
-       TALLOC_CTX *frame = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
        struct tevent_context *ev;
        struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_OK;
-
-       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
-               return cli_smb2_create_fnum(cli,
-                                       fname,
-                                       CreatFlags,
-                                       DesiredAccess,
-                                       FileAttributes,
-                                       ShareAccess,
-                                       CreateDisposition,
-                                       CreateOptions,
-                                       pfid,
-                                       NULL);
-       }
-
-       frame = talloc_stackframe();
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
 
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
@@ -1944,7 +2061,6 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
 
        ev = samba_tevent_context_init(frame);
        if (ev == NULL) {
-               status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
 
@@ -1953,16 +2069,14 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
                                CreateDisposition, CreateOptions,
                                SecurityFlags);
        if (req == NULL) {
-               status = NT_STATUS_NO_MEMORY;
                goto fail;
        }
 
-       if (!tevent_req_poll(req, ev)) {
-               status = map_nt_error_from_unix(errno);
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
 
-       status = cli_ntcreate_recv(req, pfid);
+       status = cli_ntcreate_recv(req, pfid, cr);
  fail:
        TALLOC_FREE(frame);
        return status;
@@ -1970,6 +2084,7 @@ NTSTATUS cli_ntcreate(struct cli_state *cli,
 
 struct cli_nttrans_create_state {
        uint16_t fnum;
+       struct smb_create_returns cr;
 };
 
 static void cli_nttrans_create_done(struct tevent_req *subreq);
@@ -2082,12 +2197,24 @@ static void cli_nttrans_create_done(struct tevent_req *subreq)
        if (tevent_req_nterror(req, status)) {
                return;
        }
+       state->cr.oplock_level = CVAL(param, 0);
        state->fnum = SVAL(param, 2);
+       state->cr.create_action = IVAL(param, 4);
+       state->cr.creation_time = BVAL(param, 12);
+       state->cr.last_access_time = BVAL(param, 20);
+       state->cr.last_write_time = BVAL(param, 28);
+       state->cr.change_time   = BVAL(param, 36);
+       state->cr.file_attributes = IVAL(param, 44);
+       state->cr.allocation_size = BVAL(param, 48);
+       state->cr.end_of_file   = BVAL(param, 56);
+
        TALLOC_FREE(param);
        tevent_req_done(req);
 }
 
-NTSTATUS cli_nttrans_create_recv(struct tevent_req *req, uint16_t *fnum)
+NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
+                       uint16_t *fnum,
+                       struct smb_create_returns *cr)
 {
        struct cli_nttrans_create_state *state = tevent_req_data(
                req, struct cli_nttrans_create_state);
@@ -2097,6 +2224,9 @@ NTSTATUS cli_nttrans_create_recv(struct tevent_req *req, uint16_t *fnum)
                return status;
        }
        *fnum = state->fnum;
+       if (cr != NULL) {
+               *cr = state->cr;
+       }
        return NT_STATUS_OK;
 }
 
@@ -2112,7 +2242,8 @@ NTSTATUS cli_nttrans_create(struct cli_state *cli,
                            struct security_descriptor *secdesc,
                            struct ea_struct *eas,
                            int num_eas,
-                           uint16_t *pfid)
+                           uint16_t *pfid,
+                           struct smb_create_returns *cr)
 {
        TALLOC_CTX *frame = talloc_stackframe();
        struct tevent_context *ev;
@@ -2141,7 +2272,7 @@ NTSTATUS cli_nttrans_create(struct cli_state *cli,
        if (!tevent_req_poll_ntstatus(req, ev, &status)) {
                goto fail;
        }
-       status = cli_nttrans_create_recv(req, pfid);
+       status = cli_nttrans_create_recv(req, pfid, cr);
  fail:
        TALLOC_FREE(frame);
        return status;
@@ -2353,6 +2484,7 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
        unsigned int openfn = 0;
        unsigned int dos_deny = 0;
        uint32_t access_mask, share_mode, create_disposition, create_options;
+       struct smb_create_returns cr;
 
        /* Do the initial mapping into OpenX parameters. */
        if (flags & O_CREAT) {
@@ -2433,7 +2565,8 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
                                create_disposition,
                                create_options,
                                0,
-                               pfnum);
+                               pfnum,
+                               &cr);
 
        /* Try and cope will all varients of "we don't do this call"
           and fall back to openX. */
@@ -2450,6 +2583,25 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
                goto try_openx;
        }
 
+       if (NT_STATUS_IS_OK(status) &&
+           (create_options & FILE_NON_DIRECTORY_FILE) &&
+           (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
+       {
+               /*
+                * Some (broken) servers return a valid handle
+                * for directories even if FILE_NON_DIRECTORY_FILE
+                * is set. Just close the handle and set the
+                * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
+                */
+               status = cli_close(cli, *pfnum);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+               status = NT_STATUS_FILE_IS_A_DIRECTORY;
+               /* Set this so libsmbclient can retrieve it. */
+               cli->raw_status = status;
+       }
+
        return status;
 
   try_openx:
@@ -2536,11 +2688,17 @@ NTSTATUS cli_close_recv(struct tevent_req *req)
 
 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev;
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_OK;
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_close_fnum(cli, fnum);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -3373,11 +3531,23 @@ NTSTATUS cli_getattrE(struct cli_state *cli,
                        time_t *access_time,
                        time_t *write_time)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_getattrE(cli,
+                                       fnum,
+                                       attr,
+                                       size,
+                                       change_time,
+                                       access_time,
+                                       write_time);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -3520,11 +3690,21 @@ NTSTATUS cli_getatr(struct cli_state *cli,
                        off_t *size,
                        time_t *write_time)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_getatr(cli,
+                                       fname,
+                                       attr,
+                                       size,
+                                       write_time);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -3629,11 +3809,21 @@ NTSTATUS cli_setattrE(struct cli_state *cli,
                        time_t access_time,
                        time_t write_time)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_setattrE(cli,
+                                       fnum,
+                                       change_time,
+                                       access_time,
+                                       write_time);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -3758,11 +3948,20 @@ NTSTATUS cli_setatr(struct cli_state *cli,
                uint16_t attr,
                time_t mtime)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_setatr(cli,
+                                       fname,
+                                       attr,
+                                       mtime);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -3987,11 +4186,13 @@ NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *a
 
 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -4024,6 +4225,77 @@ NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
        return status;
 }
 
+NTSTATUS cli_disk_size(struct cli_state *cli, uint64_t *bsize, uint64_t *total, uint64_t *avail)
+{
+       uint64_t sectors_per_block;
+       uint64_t bytes_per_sector;
+       int old_bsize, old_total, old_avail;
+       NTSTATUS status;
+
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_dskattr(cli, bsize, total, avail);
+       }
+
+       /*
+        * Try the trans2 disk full size info call first.
+        * We already use this in SMBC_fstatvfs_ctx().
+        * Ignore 'actual_available_units' as we only
+        * care about the quota for the caller.
+        */
+
+       status = cli_get_fs_full_size_info(cli,
+                       total,
+                       avail,
+                       NULL,
+                       &sectors_per_block,
+                       &bytes_per_sector);
+
+        /* Try and cope will all varients of "we don't do this call"
+           and fall back to cli_dskattr. */
+
+       if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
+                       NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
+               goto try_dskattr;
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (bsize) {
+               *bsize = sectors_per_block *
+                        bytes_per_sector;
+       }
+
+       return NT_STATUS_OK;
+
+  try_dskattr:
+
+       /* Old SMB1 core protocol fallback. */
+       status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       if (bsize) {
+               *bsize = (uint64_t)old_bsize;
+       }
+       if (total) {
+               *total = (uint64_t)old_total;
+       }
+       if (avail) {
+               *avail = (uint64_t)old_avail;
+       }
+       return NT_STATUS_OK;
+}
+
 /****************************************************************************
  Create and open a temporary file.
 ****************************************************************************/
@@ -4267,11 +4539,22 @@ NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
        unsigned int param_len = 0;
        uint8_t *param;
        NTSTATUS status;
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
 
-       param = talloc_array(talloc_tos(), uint8_t, 6);
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_set_ea_path(cli,
+                                       path,
+                                       ea_name,
+                                       ea_val,
+                                       ea_len);
+       }
+
+       frame = talloc_stackframe();
+
+       param = talloc_array(frame, uint8_t, 6);
        if (!param) {
-               return NT_STATUS_NO_MEMORY;
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
        }
        SSVAL(param,0,SMB_INFO_SET_EA);
        SSVAL(param,2,0);
@@ -4284,7 +4567,10 @@ NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
 
        status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
                            ea_name, ea_val, ea_len);
-       talloc_free(frame);
+
+  fail:
+
+       TALLOC_FREE(frame);
        return status;
 }
 
@@ -4298,6 +4584,14 @@ NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
 {
        uint8_t param[6];
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_set_ea_fnum(cli,
+                                       fnum,
+                                       ea_name,
+                                       ea_val,
+                                       ea_len);
+       }
+
        memset(param, 0, 6);
        SSVAL(param,0,fnum);
        SSVAL(param,2,SMB_INFO_SET_EA);
@@ -4479,11 +4773,21 @@ NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
                size_t *pnum_eas,
                struct ea_struct **pea_list)
 {
-       TALLOC_CTX *frame = talloc_stackframe();
+       TALLOC_CTX *frame = NULL;
        struct tevent_context *ev = NULL;
        struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               return cli_smb2_get_ea_list_path(cli,
+                                       path,
+                                       ctx,
+                                       pnum_eas,
+                                       pea_list);
+       }
+
+       frame = talloc_stackframe();
+
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight