s3:libsmb: make use of cli_state_[g|s]et_tid()
[Samba/gebeck_regimport.git] / source3 / libsmb / async_smb.c
blob9704ea59a9b13ff42f524e499a7ff53cfad300c7
1 /*
2 Unix SMB/CIFS implementation.
3 Infrastructure for async SMB client requests
4 Copyright (C) Volker Lendecke 2008
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/>.
20 #include "includes.h"
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_smb_req_state {
27 struct cli_state *cli;
28 uint8_t smb_command;
29 struct tevent_req *req;
30 struct cli_smb_req_state **ptr;
33 static int cli_smb_req_state_destructor(struct cli_smb_req_state *state)
35 talloc_set_destructor(state->ptr, NULL);
36 talloc_free(state->ptr);
37 return 0;
40 static int cli_smb_req_state_ptr_destructor(struct cli_smb_req_state **ptr)
42 struct cli_smb_req_state *state = *ptr;
43 void *parent = talloc_parent(state);
45 talloc_set_destructor(state, NULL);
47 talloc_reparent(state, parent, state->req);
48 talloc_free(state);
49 return 0;
52 struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx,
53 struct tevent_context *ev,
54 struct cli_state *cli,
55 uint8_t smb_command,
56 uint8_t additional_flags,
57 uint8_t wct, uint16_t *vwv,
58 int iov_count,
59 struct iovec *bytes_iov)
61 struct cli_smb_req_state *state;
62 uint8_t clear_flags = 0;
63 uint16_t additional_flags2 = 0;
64 uint16_t clear_flags2 = 0;
65 uint16_t tid = 0;
67 state = talloc_zero(mem_ctx, struct cli_smb_req_state);
68 if (state == NULL) {
69 return NULL;
71 state->cli = cli;
72 state->smb_command = smb_command;
73 state->ptr = talloc(state, struct cli_smb_req_state *);
74 if (state->ptr == NULL) {
75 talloc_free(state);
76 return NULL;
78 *state->ptr = state;
80 if (cli->case_sensitive) {
81 clear_flags |= FLAG_CASELESS_PATHNAMES;
82 } else {
83 /* Default setting, case insensitive. */
84 additional_flags |= FLAG_CASELESS_PATHNAMES;
87 if ((smb1cli_conn_capabilities(cli->conn) & CAP_DFS) && cli->dfsroot) {
88 additional_flags2 |= FLAGS2_DFS_PATHNAMES;
91 tid = cli_state_get_tid(cli);
92 state->req = smb1cli_req_create(state, ev, cli->conn, smb_command,
93 additional_flags, clear_flags,
94 additional_flags2, clear_flags2,
95 cli->timeout,
96 cli->smb1.pid,
97 tid,
98 cli->smb1.session,
99 wct, vwv, iov_count, bytes_iov);
100 if (state->req == NULL) {
101 talloc_free(state);
102 return NULL;
105 talloc_reparent(state, state->req, state->ptr);
106 talloc_set_destructor(state, cli_smb_req_state_destructor);
107 talloc_set_destructor(state->ptr, cli_smb_req_state_ptr_destructor);
109 return state->req;
112 struct tevent_req *cli_smb_send(TALLOC_CTX *mem_ctx,
113 struct tevent_context *ev,
114 struct cli_state *cli,
115 uint8_t smb_command,
116 uint8_t additional_flags,
117 uint8_t wct, uint16_t *vwv,
118 uint32_t num_bytes,
119 const uint8_t *bytes)
121 struct cli_smb_req_state *state;
122 uint8_t clear_flags = 0;
123 uint16_t additional_flags2 = 0;
124 uint16_t clear_flags2 = 0;
125 uint16_t tid = 0;
127 state = talloc_zero(mem_ctx, struct cli_smb_req_state);
128 if (state == NULL) {
129 return NULL;
131 state->cli = cli;
132 state->smb_command = smb_command;
133 state->ptr = talloc(state, struct cli_smb_req_state *);
134 if (state->ptr == NULL) {
135 talloc_free(state);
136 return NULL;
138 *state->ptr = state;
140 if (cli->case_sensitive) {
141 clear_flags |= FLAG_CASELESS_PATHNAMES;
142 } else {
143 /* Default setting, case insensitive. */
144 additional_flags |= FLAG_CASELESS_PATHNAMES;
147 if ((smb1cli_conn_capabilities(cli->conn) & CAP_DFS) && cli->dfsroot) {
148 additional_flags2 |= FLAGS2_DFS_PATHNAMES;
151 tid = cli_state_get_tid(cli);
152 state->req = smb1cli_req_send(state, ev, cli->conn, smb_command,
153 additional_flags, clear_flags,
154 additional_flags2, clear_flags2,
155 cli->timeout,
156 cli->smb1.pid,
157 tid,
158 cli->smb1.session,
159 wct, vwv, num_bytes, bytes);
160 if (state->req == NULL) {
161 talloc_free(state);
162 return NULL;
165 talloc_reparent(state, state->req, state->ptr);
166 talloc_set_destructor(state, cli_smb_req_state_destructor);
167 talloc_set_destructor(state->ptr, cli_smb_req_state_ptr_destructor);
169 return state->req;
172 NTSTATUS cli_smb_recv(struct tevent_req *req,
173 TALLOC_CTX *mem_ctx, uint8_t **pinbuf,
174 uint8_t min_wct, uint8_t *pwct, uint16_t **pvwv,
175 uint32_t *pnum_bytes, uint8_t **pbytes)
177 NTSTATUS status;
178 void *parent = talloc_parent(req);
179 struct cli_smb_req_state *state =
180 talloc_get_type(parent,
181 struct cli_smb_req_state);
182 struct iovec *recv_iov = NULL;
183 uint8_t wct = 0;
184 uint16_t *vwv = NULL;
185 uint32_t num_bytes;
186 uint8_t *bytes = NULL;
187 uint8_t *inbuf;
188 bool is_expected = false;
189 bool map_dos_errors = true;
191 if (pinbuf != NULL) {
192 *pinbuf = NULL;
194 if (pwct != NULL) {
195 *pwct = 0;
197 if (pvwv != NULL) {
198 *pvwv = NULL;
200 if (pnum_bytes != NULL) {
201 *pnum_bytes = 0;
203 if (pbytes != NULL) {
204 *pbytes = NULL;
207 status = smb1cli_req_recv(req, req,
208 &recv_iov,
209 NULL, /* phdr */
210 &wct,
211 &vwv,
212 NULL, /* pvwv_offset */
213 &num_bytes,
214 &bytes,
215 NULL, /* pbytes_offset */
216 &inbuf,
217 NULL, 0); /* expected */
219 if (state) {
220 if ((state->smb_command == SMBsesssetupX) &&
221 NT_STATUS_EQUAL(status,
222 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
224 * NT_STATUS_MORE_PROCESSING_REQUIRED is a
225 * valid return code for session setup
227 is_expected = true;
230 map_dos_errors = state->cli->map_dos_errors;
231 state->cli->raw_status = status;
232 talloc_free(state->ptr);
233 state = NULL;
236 if (NT_STATUS_IS_DOS(status) && map_dos_errors) {
237 uint8_t eclass = NT_STATUS_DOS_CLASS(status);
238 uint16_t ecode = NT_STATUS_DOS_CODE(status);
240 * TODO: is it really a good idea to do a mapping here?
242 * The old cli_pull_error() also does it, so I do not change
243 * the behavior yet.
245 status = dos_to_ntstatus(eclass, ecode);
248 if (!NT_STATUS_IS_ERR(status)) {
249 is_expected = true;
252 if (!is_expected) {
253 TALLOC_FREE(recv_iov);
254 return status;
257 if (wct < min_wct) {
258 TALLOC_FREE(recv_iov);
259 return NT_STATUS_INVALID_NETWORK_RESPONSE;
262 if (pwct != NULL) {
263 *pwct = wct;
265 if (pvwv != NULL) {
266 *pvwv = vwv;
268 if (pnum_bytes != NULL) {
269 *pnum_bytes = num_bytes;
271 if (pbytes != NULL) {
272 *pbytes = bytes;
275 if (pinbuf != NULL && mem_ctx != NULL) {
276 if (talloc_reference_count(inbuf) == 0) {
277 *pinbuf = talloc_move(mem_ctx, &inbuf);
278 TALLOC_FREE(recv_iov);
279 } else {
280 *pinbuf = inbuf;
282 } else if (mem_ctx != NULL) {
283 if (talloc_reference_count(inbuf) == 0) {
284 (void)talloc_move(mem_ctx, &inbuf);
285 TALLOC_FREE(recv_iov);
289 return status;