Coverage Report

Created: 2025-07-23 07:04

/src/samba/libcli/smb/smb2cli_write.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   Unix SMB/CIFS implementation.
3
   smb2 lib
4
   Copyright (C) Volker Lendecke 2011
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*/
19
20
#include "includes.h"
21
#include "system/network.h"
22
#include "lib/util/tevent_ntstatus.h"
23
#include "smb_common.h"
24
#include "smbXcli_base.h"
25
26
struct smb2cli_write_state {
27
  uint8_t fixed[48];
28
  uint8_t dyn_pad[1];
29
  uint32_t written;
30
};
31
32
static void smb2cli_write_done(struct tevent_req *subreq);
33
34
struct tevent_req *smb2cli_write_send(TALLOC_CTX *mem_ctx,
35
              struct tevent_context *ev,
36
              struct smbXcli_conn *conn,
37
              uint32_t timeout_msec,
38
              struct smbXcli_session *session,
39
              struct smbXcli_tcon *tcon,
40
              uint32_t length,
41
              uint64_t offset,
42
              uint64_t fid_persistent,
43
              uint64_t fid_volatile,
44
              uint32_t remaining_bytes,
45
              uint32_t flags,
46
              const uint8_t *data)
47
0
{
48
0
  struct tevent_req *req, *subreq;
49
0
  struct smb2cli_write_state *state;
50
0
  uint8_t *fixed;
51
0
  const uint8_t *dyn;
52
0
  size_t dyn_len;
53
54
0
  req = tevent_req_create(mem_ctx, &state,
55
0
        struct smb2cli_write_state);
56
0
  if (req == NULL) {
57
0
    return NULL;
58
0
  }
59
60
0
  fixed = state->fixed;
61
62
0
  SSVAL(fixed, 0, 49);
63
0
  SSVAL(fixed, 2, SMB2_HDR_BODY + 48);
64
0
  SIVAL(fixed, 4, length);
65
0
  SBVAL(fixed, 8, offset);
66
0
  SBVAL(fixed, 16, fid_persistent);
67
0
  SBVAL(fixed, 24, fid_volatile);
68
0
  SIVAL(fixed, 36, remaining_bytes);
69
0
  SIVAL(fixed, 44, flags);
70
71
0
  if (length > 0) {
72
0
    dyn = data;
73
0
    dyn_len = length;
74
0
  } else {
75
0
    dyn = state->dyn_pad;;
76
0
    dyn_len = sizeof(state->dyn_pad);
77
0
  }
78
79
0
  subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_WRITE,
80
0
          0, 0, /* flags */
81
0
          timeout_msec,
82
0
          tcon,
83
0
          session,
84
0
          state->fixed, sizeof(state->fixed),
85
0
          dyn, dyn_len,
86
0
          0); /* max_dyn_len */
87
0
  if (tevent_req_nomem(subreq, req)) {
88
0
    return tevent_req_post(req, ev);
89
0
  }
90
0
  tevent_req_set_callback(subreq, smb2cli_write_done, req);
91
0
  return req;
92
0
}
93
94
static void smb2cli_write_done(struct tevent_req *subreq)
95
0
{
96
0
  struct tevent_req *req =
97
0
    tevent_req_callback_data(subreq,
98
0
    struct tevent_req);
99
0
  struct smb2cli_write_state *state =
100
0
    tevent_req_data(req,
101
0
    struct smb2cli_write_state);
102
0
  NTSTATUS status;
103
0
  struct iovec *iov;
104
0
  static const struct smb2cli_req_expected_response expected[] = {
105
0
  {
106
0
    .status = NT_STATUS_OK,
107
0
    .body_size = 0x11
108
0
  }
109
0
  };
110
111
0
  status = smb2cli_req_recv(subreq, state, &iov,
112
0
          expected, ARRAY_SIZE(expected));
113
0
  TALLOC_FREE(subreq);
114
0
  if (tevent_req_nterror(req, status)) {
115
0
    return;
116
0
  }
117
0
  state->written = IVAL(iov[1].iov_base, 4);
118
0
  tevent_req_done(req);
119
0
}
120
121
NTSTATUS smb2cli_write_recv(struct tevent_req *req, uint32_t *written)
122
0
{
123
0
  struct smb2cli_write_state *state =
124
0
    tevent_req_data(req,
125
0
    struct smb2cli_write_state);
126
0
  NTSTATUS status;
127
128
0
  if (tevent_req_is_nterror(req, &status)) {
129
0
    tevent_req_received(req);
130
0
    return status;
131
0
  }
132
0
  if (written) {
133
0
    *written = state->written;
134
0
  }
135
0
  tevent_req_received(req);
136
0
  return NT_STATUS_OK;
137
0
}
138
139
NTSTATUS smb2cli_write(struct smbXcli_conn *conn,
140
           uint32_t timeout_msec,
141
           struct smbXcli_session *session,
142
           struct smbXcli_tcon *tcon,
143
           uint32_t length,
144
           uint64_t offset,
145
           uint64_t fid_persistent,
146
           uint64_t fid_volatile,
147
           uint32_t remaining_bytes,
148
           uint32_t flags,
149
           const uint8_t *data,
150
           uint32_t *written)
151
0
{
152
0
  TALLOC_CTX *frame = talloc_stackframe();
153
0
  struct tevent_context *ev;
154
0
  struct tevent_req *req;
155
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
156
157
0
  if (smbXcli_conn_has_async_calls(conn)) {
158
    /*
159
     * Can't use sync call while an async call is in flight
160
     */
161
0
    status = NT_STATUS_INVALID_PARAMETER;
162
0
    goto fail;
163
0
  }
164
0
  ev = samba_tevent_context_init(frame);
165
0
  if (ev == NULL) {
166
0
    goto fail;
167
0
  }
168
0
  req = smb2cli_write_send(frame, ev, conn, timeout_msec,
169
0
         session, tcon,
170
0
         length, offset,
171
0
         fid_persistent, fid_volatile,
172
0
         remaining_bytes, flags, data);
173
0
  if (req == NULL) {
174
0
    goto fail;
175
0
  }
176
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
177
0
    goto fail;
178
0
  }
179
0
  status = smb2cli_write_recv(req, written);
180
0
 fail:
181
0
  TALLOC_FREE(frame);
182
0
  return status;
183
0
}