Coverage Report

Created: 2025-07-23 07:04

/src/samba/source3/libsmb/clitrans.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   Unix SMB/CIFS implementation.
3
   client transaction calls
4
   Copyright (C) Andrew Tridgell 1994-1998
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 "source3/include/client.h"
22
#include "source3/libsmb/proto.h"
23
#include "../lib/util/tevent_ntstatus.h"
24
#include "async_smb.h"
25
#include "../libcli/smb/smbXcli_base.h"
26
27
struct cli_trans_state {
28
  struct cli_state *cli;
29
  struct tevent_req *subreq;
30
  uint16_t recv_flags2;
31
  uint16_t *setup;
32
  uint8_t num_setup;
33
  uint8_t *param;
34
  uint32_t num_param;
35
  uint8_t *data;
36
  uint32_t num_data;
37
};
38
39
static void cli_trans_done(struct tevent_req *subreq);
40
static bool cli_trans_cancel(struct tevent_req *req);
41
42
struct tevent_req *cli_trans_send(
43
  TALLOC_CTX *mem_ctx, struct tevent_context *ev,
44
  struct cli_state *cli, uint16_t additional_flags2, uint8_t cmd,
45
  const char *pipe_name, uint16_t fid, uint16_t function, int flags,
46
  uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
47
  uint8_t *param, uint32_t num_param, uint32_t max_param,
48
  uint8_t *data, uint32_t num_data, uint32_t max_data)
49
0
{
50
0
  struct tevent_req *req;
51
0
  struct cli_trans_state *state;
52
0
  uint8_t additional_flags = 0;
53
0
  uint8_t clear_flags = 0;
54
0
  uint16_t clear_flags2 = 0;
55
56
0
  req = tevent_req_create(mem_ctx, &state, struct cli_trans_state);
57
0
  if (req == NULL) {
58
0
    return NULL;
59
0
  }
60
0
  state->cli = cli;
61
62
0
  state->subreq = smb1cli_trans_send(state, ev,
63
0
             cli->conn, cmd,
64
0
             additional_flags, clear_flags,
65
0
             additional_flags2, clear_flags2,
66
0
             cli->timeout,
67
0
             cli->smb1.pid,
68
0
             cli->smb1.tcon,
69
0
             cli->smb1.session,
70
0
             pipe_name, fid, function, flags,
71
0
             setup, num_setup, max_setup,
72
0
             param, num_param, max_param,
73
0
             data, num_data, max_data);
74
0
  if (tevent_req_nomem(state->subreq, req)) {
75
0
    return tevent_req_post(req, ev);
76
0
  }
77
0
  tevent_req_set_callback(state->subreq, cli_trans_done, req);
78
0
  tevent_req_set_cancel_fn(req, cli_trans_cancel);
79
0
  return req;
80
0
}
81
82
static bool cli_trans_cancel(struct tevent_req *req)
83
0
{
84
0
  struct cli_trans_state *state = tevent_req_data(
85
0
    req, struct cli_trans_state);
86
0
  bool ok;
87
88
0
  ok = tevent_req_cancel(state->subreq);
89
0
  return ok;
90
0
}
91
92
static void cli_trans_done(struct tevent_req *subreq)
93
0
{
94
0
  struct tevent_req *req = tevent_req_callback_data(
95
0
    subreq, struct tevent_req);
96
0
  struct cli_trans_state *state = tevent_req_data(
97
0
    req, struct cli_trans_state);
98
0
  NTSTATUS status;
99
100
0
  status = smb1cli_trans_recv(
101
0
    subreq,
102
0
    state,
103
0
    &state->recv_flags2,
104
0
    &state->setup, 0, &state->num_setup,
105
0
    &state->param, 0, &state->num_param,
106
0
    &state->data, 0, &state->num_data);
107
0
  TALLOC_FREE(subreq);
108
0
  if (tevent_req_nterror(req, status)) {
109
0
    return;
110
0
  }
111
0
  tevent_req_done(req);
112
0
}
113
114
NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
115
      uint16_t *recv_flags2,
116
      uint16_t **setup, uint8_t min_setup,
117
      uint8_t *num_setup,
118
      uint8_t **param, uint32_t min_param,
119
      uint32_t *num_param,
120
      uint8_t **data, uint32_t min_data,
121
      uint32_t *num_data)
122
0
{
123
0
  struct cli_trans_state *state = tevent_req_data(
124
0
    req, struct cli_trans_state);
125
0
  NTSTATUS status = NT_STATUS_OK;
126
0
  bool map_dos_errors = true;
127
128
0
  if (tevent_req_is_nterror(req, &status)) {
129
0
    goto map_error;
130
0
  }
131
132
0
  if ((state->num_setup < min_setup) ||
133
0
      (state->num_param < min_param) ||
134
0
      (state->num_data < min_data)) {
135
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
136
0
  }
137
138
0
  if (recv_flags2 != NULL) {
139
0
    *recv_flags2 = state->recv_flags2;
140
0
  }
141
0
  if (setup != NULL) {
142
0
    *setup = talloc_move(mem_ctx, &state->setup);
143
0
    *num_setup = state->num_setup;
144
0
  }
145
0
  if (param != NULL) {
146
0
    *param = talloc_move(mem_ctx, &state->param);
147
0
    *num_param = state->num_param;
148
0
  }
149
0
  if (data != NULL) {
150
0
    *data = talloc_move(mem_ctx, &state->data);
151
0
    *num_data = state->num_data;
152
0
  }
153
154
0
map_error:
155
0
  map_dos_errors = state->cli->map_dos_errors;
156
157
0
  if (NT_STATUS_IS_DOS(status) && map_dos_errors) {
158
0
    uint8_t eclass = NT_STATUS_DOS_CLASS(status);
159
0
    uint16_t ecode = NT_STATUS_DOS_CODE(status);
160
    /*
161
     * TODO: is it really a good idea to do a mapping here?
162
     *
163
     * The old cli_pull_error() also does it, so I do not change
164
     * the behavior yet.
165
     */
166
0
    status = dos_to_ntstatus(eclass, ecode);
167
0
  }
168
169
0
  return status;
170
0
}
171
172
NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
173
       uint8_t trans_cmd,
174
       const char *pipe_name, uint16_t fid, uint16_t function,
175
       int flags,
176
       uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
177
       uint8_t *param, uint32_t num_param, uint32_t max_param,
178
       uint8_t *data, uint32_t num_data, uint32_t max_data,
179
       uint16_t *recv_flags2,
180
       uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
181
       uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
182
       uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata)
183
0
{
184
0
  TALLOC_CTX *frame = talloc_stackframe();
185
0
  struct tevent_context *ev;
186
0
  struct tevent_req *req;
187
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
188
189
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
190
    /*
191
     * Can't use sync call while an async call is in flight
192
     */
193
0
    status = NT_STATUS_INVALID_PARAMETER;
194
0
    goto fail;
195
0
  }
196
0
  ev = samba_tevent_context_init(frame);
197
0
  if (ev == NULL) {
198
0
    goto fail;
199
0
  }
200
0
  req = cli_trans_send(
201
0
    frame,    /* mem_ctx */
202
0
    ev,   /* ev */
203
0
    cli,    /* cli */
204
0
    0,    /* additional_flags2 */
205
0
    trans_cmd,  /* cmd */
206
0
    pipe_name, fid, function, flags,
207
0
    setup, num_setup, max_setup,
208
0
    param, num_param, max_param,
209
0
    data, num_data, max_data);
210
0
  if (req == NULL) {
211
0
    goto fail;
212
0
  }
213
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
214
0
    goto fail;
215
0
  }
216
0
  status = cli_trans_recv(
217
0
    req, mem_ctx, recv_flags2,
218
0
    rsetup, min_rsetup, num_rsetup,
219
0
    rparam, min_rparam, num_rparam,
220
0
    rdata, min_rdata, num_rdata);
221
0
fail:
222
0
  TALLOC_FREE(frame);
223
0
  return status;
224
0
}