Coverage Report

Created: 2026-07-25 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/libcli/smb/smb1cli_write.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
4
   Copyright (C) Gregor Beck 2013
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 smb1cli_writex_state {
27
  uint32_t size;
28
  uint16_t vwv[14];
29
  uint32_t written;
30
  uint16_t available;
31
  uint8_t pad;
32
  struct iovec iov[2];
33
};
34
35
static void smb1cli_writex_done(struct tevent_req *subreq);
36
37
/**
38
 * Send an asynchrounus SMB_COM_WRITE_ANDX request.
39
 * <a href="http://msdn.microsoft.com/en-us/library/ee441954.aspx">MS-CIFS 2.2.4.43.1</a>
40
 * @see smb1cli_writex_recv(), smb1cli_writex()
41
 *
42
 * @param[in] mem_ctx The memory context for the result.
43
 * @param[in] ev The event context to work on.
44
 * @param[in] conn The smb connection.
45
 * @param[in] timeout_msec If positive a timeout for the request.
46
 * @param[in] pid The process identifier
47
 * @param[in] tcon The smb tree connect.
48
 * @param[in] session The smb session.
49
 * @param[in] fnum The file id of the file the data should be written to.
50
 * @param[in] mode A bitfield containing the write mode.
51
 * @param[in] buf The data to be written to the file.
52
 * @param[in] offset The offset in bytes from the begin of file where to write.
53
 * @param[in] size The number of bytes to write.
54
 *
55
 * @return a tevent_req or NULL
56
 */
57
struct tevent_req *smb1cli_writex_send(TALLOC_CTX *mem_ctx,
58
               struct tevent_context *ev,
59
               struct smbXcli_conn *conn,
60
               uint32_t timeout_msec,
61
               uint32_t pid,
62
               struct smbXcli_tcon *tcon,
63
               struct smbXcli_session *session,
64
               uint16_t fnum,
65
               uint16_t mode,
66
               const uint8_t *buf,
67
               uint64_t offset,
68
               uint32_t size)
69
0
{
70
0
  struct tevent_req *req, *subreq;
71
0
  struct smb1cli_writex_state *state;
72
0
  bool bigoffset = ((smb1cli_conn_capabilities(conn) & CAP_LARGE_FILES) != 0);
73
0
  uint8_t wct = bigoffset ? 14 : 12;
74
0
  uint16_t *vwv;
75
0
  uint16_t data_offset =
76
0
    smb1cli_req_wct_ofs(NULL, 0) /* reqs_before */
77
0
    + 1          /* the wct field */
78
0
    + wct * 2        /* vwv */
79
0
    + 2          /* num_bytes field */
80
0
    + 1;           /* pad */
81
0
  NTSTATUS status;
82
83
0
  req = tevent_req_create(mem_ctx, &state, struct smb1cli_writex_state);
84
0
  if (req == NULL) {
85
0
    return NULL;
86
0
  }
87
88
0
  state->size = size;
89
90
0
  vwv = state->vwv;
91
92
0
  SCVAL(vwv+0, 0, 0xFF);
93
0
  SCVAL(vwv+0, 1, 0);
94
0
  SSVAL(vwv+1, 0, 0);
95
0
  SSVAL(vwv+2, 0, fnum);
96
0
  SIVAL(vwv+3, 0, offset);
97
0
  SIVAL(vwv+5, 0, 0);
98
0
  SSVAL(vwv+7, 0, mode);
99
0
  SSVAL(vwv+8, 0, 0);
100
0
  SSVAL(vwv+9, 0, (state->size>>16));
101
0
  SSVAL(vwv+10, 0, state->size);
102
0
  SSVAL(vwv+11, 0, data_offset);
103
104
0
  if (bigoffset) {
105
0
    SIVAL(vwv+12, 0, (((uint64_t)offset)>>32) & 0xffffffff);
106
0
  }
107
108
0
  state->pad = 0;
109
0
  state->iov[0].iov_base = (void *)&state->pad;
110
0
  state->iov[0].iov_len = 1;
111
0
  state->iov[1].iov_base = discard_const_p(void, buf);
112
0
  state->iov[1].iov_len = state->size;
113
114
0
  subreq = smb1cli_req_create(state, ev, conn, SMBwriteX,
115
0
            0, 0, /* *_flags */
116
0
            0, 0, /* *_flags2 */
117
0
            timeout_msec, pid, tcon, session,
118
0
            wct, vwv,
119
0
            ARRAY_SIZE(state->iov), state->iov);
120
0
  if (tevent_req_nomem(subreq, req)) {
121
0
    return tevent_req_post(req, ev);
122
0
  }
123
0
  tevent_req_set_callback(subreq, smb1cli_writex_done, req);
124
125
0
  status = smb1cli_req_chain_submit(&subreq, 1);
126
0
  if (tevent_req_nterror(req, status)) {
127
0
    return tevent_req_post(req, ev);
128
0
  }
129
130
0
  return req;
131
0
}
132
133
static void smb1cli_writex_done(struct tevent_req *subreq)
134
0
{
135
0
  struct tevent_req *req = tevent_req_callback_data(
136
0
    subreq, struct tevent_req);
137
0
  struct smb1cli_writex_state *state = tevent_req_data(
138
0
    req, struct smb1cli_writex_state);
139
0
  struct iovec *recv_iov = NULL;
140
0
  uint8_t wct;
141
0
  uint16_t *vwv;
142
0
  NTSTATUS status;
143
0
  static const struct smb1cli_req_expected_response expected[] = {
144
0
  {
145
0
    .status = NT_STATUS_OK,
146
0
    .wct = 0x06
147
0
  },
148
0
  };
149
150
0
  status = smb1cli_req_recv(subreq, state,
151
0
          &recv_iov,
152
0
          NULL, /* phdr */
153
0
          &wct,
154
0
          &vwv,
155
0
          NULL, /* pvwv_offset */
156
0
          NULL, /* num_bytes */
157
0
          NULL, /* bytes */
158
0
          NULL, /* pbytes_offset */
159
0
          NULL, /* inbuf */
160
0
          expected, ARRAY_SIZE(expected));
161
0
  TALLOC_FREE(subreq);
162
0
  if (tevent_req_nterror(req, status)) {
163
0
    return;
164
0
  }
165
166
0
  state->written = SVAL(vwv+2, 0);
167
0
  if (state->size > UINT16_MAX) {
168
    /*
169
     * It is important that we only set the
170
     * high bits only if we asked for a large write.
171
     *
172
     * OS/2 print shares get this wrong and may send
173
     * invalid values.
174
     *
175
     * See bug #5326.
176
     */
177
0
    state->written |= SVAL(vwv+4, 0)<<16;
178
0
  }
179
0
  state->available = SVAL(vwv+3, 0);
180
181
0
  tevent_req_done(req);
182
0
}
183
184
/**
185
 * Receive the response to an asynchronous SMB_COM_WRITE_ANDX request.
186
 * <a href="http://msdn.microsoft.com/en-us/library/ee441673.aspx">MS-CIFS:2.2.4.43.2</a>
187
 *
188
 *
189
 * @param[in] req req A tevent request created with smb1cli_writex_send()
190
 * @param[out] pwritten The number of bytes written to the file.
191
 * @param[out] pavailable Valid if writing to a named pipe or IO device.
192
 *
193
 * @return NT_STATUS_OK on success.
194
 */
195
NTSTATUS smb1cli_writex_recv(struct tevent_req *req, uint32_t *pwritten, uint16_t *pavailable)
196
0
{
197
0
  struct smb1cli_writex_state *state = tevent_req_data(
198
0
    req, struct smb1cli_writex_state);
199
0
  NTSTATUS status;
200
201
0
  if (tevent_req_is_nterror(req, &status)) {
202
0
    return status;
203
0
  }
204
0
  if (pwritten != NULL) {
205
0
    *pwritten = state->written;
206
0
  }
207
0
  if (pavailable != NULL) {
208
0
    *pavailable = state->available;
209
0
  }
210
0
  return NT_STATUS_OK;
211
0
}
212
213
/**
214
 * Send an synchrounus SMB_COM_WRITE_ANDX request.
215
 * <a href="http://msdn.microsoft.com/en-us/library/ee441848.aspx">MS-CIFS 2.2.4.43</a>
216
 * @see smb1cli_writex_send(), smb1cli_writex_recv()
217
 *
218
 * @param[in] conn The smb connection.
219
 * @param[in] timeout_msec If positive a timeout for the request.
220
 * @param[in] pid The process identifier
221
 * @param[in] tcon The smb tree connect.
222
 * @param[in] session The smb session.
223
 * @param[in] fnum The file id of the file the data should be written to.
224
 * @param[in] mode A bitfield containing the write mode.
225
 * @param[in] buf The data to be written to the file.
226
 * @param[in] offset The offset in bytes from the begin of file where to write.
227
 * @param[in] size The number of bytes to write.
228
 * @param[out] pwritten The number of bytes written to the file.
229
 * @param[out] pavailable Valid if writing to a named pipe or IO device.
230
 *
231
 * @return NT_STATUS_OK on success.
232
 */
233
NTSTATUS smb1cli_writex(struct smbXcli_conn *conn,
234
      uint32_t timeout_msec,
235
      uint32_t pid,
236
      struct smbXcli_tcon *tcon,
237
      struct smbXcli_session *session,
238
      uint16_t fnum,
239
      uint16_t mode,
240
      const uint8_t *buf,
241
      uint64_t offset,
242
      uint32_t size,
243
      uint32_t *pwritten,
244
      uint16_t *pavailable)
245
0
{
246
0
  TALLOC_CTX *frame = NULL;
247
0
  struct tevent_context *ev;
248
0
  struct tevent_req *req;
249
0
  NTSTATUS status = NT_STATUS_OK;
250
251
0
  frame = talloc_stackframe();
252
253
0
  if (smbXcli_conn_has_async_calls(conn)) {
254
    /*
255
     * Can't use sync call while an async call is in flight
256
     */
257
0
    status = NT_STATUS_INVALID_PARAMETER;
258
0
    goto done;
259
0
  }
260
261
0
  ev = samba_tevent_context_init(frame);
262
0
  if (ev == NULL) {
263
0
    status = NT_STATUS_NO_MEMORY;
264
0
    goto done;
265
0
  }
266
267
0
  req = smb1cli_writex_send(frame, ev, conn,
268
0
          timeout_msec,
269
0
          pid, tcon, session,
270
0
          fnum, mode, buf, offset, size);
271
0
  if (req == NULL) {
272
0
    status = NT_STATUS_NO_MEMORY;
273
0
    goto done;
274
0
  }
275
276
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
277
0
    goto done;
278
0
  }
279
280
0
  status = smb1cli_writex_recv(req, pwritten, pavailable);
281
0
done:
282
  TALLOC_FREE(frame);
283
0
  return status;
284
0
}