2 Unix SMB/CIFS implementation.
3 client transaction calls
4 Copyright (C) Andrew Tridgell 1994-1998
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.
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.
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/>.
21 #include "libsmb/libsmb.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.h"
24 #include "../libcli/smb/smbXcli_base.h"
26 struct cli_trans_state
{
27 struct cli_state
*cli
;
28 struct tevent_req
*subreq
;
38 static void cli_trans_done(struct tevent_req
*subreq
);
39 static bool cli_trans_cancel(struct tevent_req
*req
);
41 struct tevent_req
*cli_trans_send(
42 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
43 struct cli_state
*cli
, uint16_t additional_flags2
, uint8_t cmd
,
44 const char *pipe_name
, uint16_t fid
, uint16_t function
, int flags
,
45 uint16_t *setup
, uint8_t num_setup
, uint8_t max_setup
,
46 uint8_t *param
, uint32_t num_param
, uint32_t max_param
,
47 uint8_t *data
, uint32_t num_data
, uint32_t max_data
)
49 struct tevent_req
*req
;
50 struct cli_trans_state
*state
;
51 uint8_t additional_flags
= 0;
52 uint8_t clear_flags
= 0;
53 uint16_t clear_flags2
= 0;
55 req
= tevent_req_create(mem_ctx
, &state
, struct cli_trans_state
);
61 state
->subreq
= smb1cli_trans_send(state
, ev
,
63 additional_flags
, clear_flags
,
64 additional_flags2
, clear_flags2
,
69 pipe_name
, fid
, function
, flags
,
70 setup
, num_setup
, max_setup
,
71 param
, num_param
, max_param
,
72 data
, num_data
, max_data
);
73 if (tevent_req_nomem(state
->subreq
, req
)) {
74 return tevent_req_post(req
, ev
);
76 tevent_req_set_callback(state
->subreq
, cli_trans_done
, req
);
77 tevent_req_set_cancel_fn(req
, cli_trans_cancel
);
81 static bool cli_trans_cancel(struct tevent_req
*req
)
83 struct cli_trans_state
*state
= tevent_req_data(
84 req
, struct cli_trans_state
);
87 ok
= tevent_req_cancel(state
->subreq
);
91 static void cli_trans_done(struct tevent_req
*subreq
)
93 struct tevent_req
*req
= tevent_req_callback_data(
94 subreq
, struct tevent_req
);
95 struct cli_trans_state
*state
= tevent_req_data(
96 req
, struct cli_trans_state
);
99 status
= smb1cli_trans_recv(
103 &state
->setup
, 0, &state
->num_setup
,
104 &state
->param
, 0, &state
->num_param
,
105 &state
->data
, 0, &state
->num_data
);
107 if (tevent_req_nterror(req
, status
)) {
110 tevent_req_done(req
);
113 NTSTATUS
cli_trans_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
114 uint16_t *recv_flags2
,
115 uint16_t **setup
, uint8_t min_setup
,
117 uint8_t **param
, uint32_t min_param
,
119 uint8_t **data
, uint32_t min_data
,
122 struct cli_trans_state
*state
= tevent_req_data(
123 req
, struct cli_trans_state
);
124 NTSTATUS status
= NT_STATUS_OK
;
125 bool map_dos_errors
= true;
127 if (tevent_req_is_nterror(req
, &status
)) {
131 if ((state
->num_setup
< min_setup
) ||
132 (state
->num_param
< min_param
) ||
133 (state
->num_data
< min_data
)) {
134 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
137 if (recv_flags2
!= NULL
) {
138 *recv_flags2
= state
->recv_flags2
;
141 *setup
= talloc_move(mem_ctx
, &state
->setup
);
142 *num_setup
= state
->num_setup
;
145 *param
= talloc_move(mem_ctx
, &state
->param
);
146 *num_param
= state
->num_param
;
149 *data
= talloc_move(mem_ctx
, &state
->data
);
150 *num_data
= state
->num_data
;
154 map_dos_errors
= state
->cli
->map_dos_errors
;
155 state
->cli
->raw_status
= status
;
157 if (NT_STATUS_IS_DOS(status
) && map_dos_errors
) {
158 uint8_t eclass
= NT_STATUS_DOS_CLASS(status
);
159 uint16_t ecode
= NT_STATUS_DOS_CODE(status
);
161 * TODO: is it really a good idea to do a mapping here?
163 * The old cli_pull_error() also does it, so I do not change
166 status
= dos_to_ntstatus(eclass
, ecode
);
172 NTSTATUS
cli_trans(TALLOC_CTX
*mem_ctx
, struct cli_state
*cli
,
174 const char *pipe_name
, uint16_t fid
, uint16_t function
,
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
)
184 TALLOC_CTX
*frame
= talloc_stackframe();
185 struct tevent_context
*ev
;
186 struct tevent_req
*req
;
187 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
189 if (smbXcli_conn_has_async_calls(cli
->conn
)) {
191 * Can't use sync call while an async call is in flight
193 status
= NT_STATUS_INVALID_PARAMETER
;
196 ev
= samba_tevent_context_init(frame
);
200 req
= cli_trans_send(
204 0, /* additional_flags2 */
206 pipe_name
, fid
, function
, flags
,
207 setup
, num_setup
, max_setup
,
208 param
, num_param
, max_param
,
209 data
, num_data
, max_data
);
213 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
216 status
= cli_trans_recv(
217 req
, mem_ctx
, recv_flags2
,
218 rsetup
, min_rsetup
, num_rsetup
,
219 rparam
, min_rparam
, num_rparam
,
220 rdata
, min_rdata
, num_rdata
);