source: vendor/current/source3/libsmb/async_smb.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 6.3 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Infrastructure for async SMB client requests
4 Copyright (C) Volker Lendecke 2008
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 "libsmb/libsmb.h"
22#include "../lib/util/tevent_ntstatus.h"
23#include "async_smb.h"
24#include "../libcli/smb/smbXcli_base.h"
25
26struct 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;
31};
32
33static int cli_smb_req_state_destructor(struct cli_smb_req_state *state)
34{
35 talloc_set_destructor(state->ptr, NULL);
36 talloc_free(state->ptr);
37 return 0;
38}
39
40static int cli_smb_req_state_ptr_destructor(struct cli_smb_req_state **ptr)
41{
42 struct cli_smb_req_state *state = *ptr;
43 void *parent = talloc_parent(state);
44
45 talloc_set_destructor(state, NULL);
46
47 talloc_reparent(state, parent, state->req);
48 talloc_free(state);
49 return 0;
50}
51
52struct 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)
60{
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
66 state = talloc_zero(mem_ctx, struct cli_smb_req_state);
67 if (state == NULL) {
68 return NULL;
69 }
70 state->cli = cli;
71 state->smb_command = smb_command;
72 state->ptr = talloc(state, struct cli_smb_req_state *);
73 if (state->ptr == NULL) {
74 talloc_free(state);
75 return NULL;
76 }
77 *state->ptr = state;
78
79 state->req = smb1cli_req_create(state, ev, cli->conn, smb_command,
80 additional_flags, clear_flags,
81 additional_flags2, clear_flags2,
82 cli->timeout,
83 cli->smb1.pid,
84 cli->smb1.tcon,
85 cli->smb1.session,
86 wct, vwv, iov_count, bytes_iov);
87 if (state->req == NULL) {
88 talloc_free(state);
89 return NULL;
90 }
91
92 talloc_reparent(state, state->req, state->ptr);
93 talloc_set_destructor(state, cli_smb_req_state_destructor);
94 talloc_set_destructor(state->ptr, cli_smb_req_state_ptr_destructor);
95
96 return state->req;
97}
98
99struct tevent_req *cli_smb_send(TALLOC_CTX *mem_ctx,
100 struct tevent_context *ev,
101 struct cli_state *cli,
102 uint8_t smb_command,
103 uint8_t additional_flags,
104 uint8_t wct, uint16_t *vwv,
105 uint32_t num_bytes,
106 const uint8_t *bytes)
107{
108 struct cli_smb_req_state *state;
109 uint8_t clear_flags = 0;
110 uint16_t additional_flags2 = 0;
111 uint16_t clear_flags2 = 0;
112
113 state = talloc_zero(mem_ctx, struct cli_smb_req_state);
114 if (state == NULL) {
115 return NULL;
116 }
117 state->cli = cli;
118 state->smb_command = smb_command;
119 state->ptr = talloc(state, struct cli_smb_req_state *);
120 if (state->ptr == NULL) {
121 talloc_free(state);
122 return NULL;
123 }
124 *state->ptr = state;
125
126 state->req = smb1cli_req_send(state, ev, cli->conn, smb_command,
127 additional_flags, clear_flags,
128 additional_flags2, clear_flags2,
129 cli->timeout,
130 cli->smb1.pid,
131 cli->smb1.tcon,
132 cli->smb1.session,
133 wct, vwv, num_bytes, bytes);
134 if (state->req == NULL) {
135 talloc_free(state);
136 return NULL;
137 }
138
139 talloc_reparent(state, state->req, state->ptr);
140 talloc_set_destructor(state, cli_smb_req_state_destructor);
141 talloc_set_destructor(state->ptr, cli_smb_req_state_ptr_destructor);
142
143 return state->req;
144}
145
146NTSTATUS cli_smb_recv(struct tevent_req *req,
147 TALLOC_CTX *mem_ctx, uint8_t **pinbuf,
148 uint8_t min_wct, uint8_t *pwct, uint16_t **pvwv,
149 uint32_t *pnum_bytes, uint8_t **pbytes)
150{
151 NTSTATUS status;
152 void *parent = talloc_parent(req);
153 struct cli_smb_req_state *state =
154 talloc_get_type(parent,
155 struct cli_smb_req_state);
156 struct iovec *recv_iov = NULL;
157 uint8_t wct = 0;
158 uint16_t *vwv = NULL;
159 uint32_t num_bytes;
160 uint8_t *bytes = NULL;
161 uint8_t *inbuf;
162 bool is_expected = false;
163 bool map_dos_errors = true;
164
165 if (pinbuf != NULL) {
166 *pinbuf = NULL;
167 }
168 if (pwct != NULL) {
169 *pwct = 0;
170 }
171 if (pvwv != NULL) {
172 *pvwv = NULL;
173 }
174 if (pnum_bytes != NULL) {
175 *pnum_bytes = 0;
176 }
177 if (pbytes != NULL) {
178 *pbytes = NULL;
179 }
180
181 status = smb1cli_req_recv(req, req,
182 &recv_iov,
183 NULL, /* phdr */
184 &wct,
185 &vwv,
186 NULL, /* pvwv_offset */
187 &num_bytes,
188 &bytes,
189 NULL, /* pbytes_offset */
190 &inbuf,
191 NULL, 0); /* expected */
192
193 if (state) {
194 if ((state->smb_command == SMBsesssetupX) &&
195 NT_STATUS_EQUAL(status,
196 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
197 /*
198 * NT_STATUS_MORE_PROCESSING_REQUIRED is a
199 * valid return code for session setup
200 */
201 is_expected = true;
202 }
203
204 map_dos_errors = state->cli->map_dos_errors;
205 state->cli->raw_status = status;
206 talloc_free(state->ptr);
207 state = NULL;
208 }
209
210 if (NT_STATUS_IS_DOS(status) && map_dos_errors) {
211 uint8_t eclass = NT_STATUS_DOS_CLASS(status);
212 uint16_t ecode = NT_STATUS_DOS_CODE(status);
213 /*
214 * TODO: is it really a good idea to do a mapping here?
215 *
216 * The old cli_pull_error() also does it, so I do not change
217 * the behavior yet.
218 */
219 status = dos_to_ntstatus(eclass, ecode);
220 }
221
222 if (!NT_STATUS_IS_ERR(status)) {
223 is_expected = true;
224 }
225
226 if (!is_expected) {
227 TALLOC_FREE(recv_iov);
228 return status;
229 }
230
231 if (wct < min_wct) {
232 TALLOC_FREE(recv_iov);
233 return NT_STATUS_INVALID_NETWORK_RESPONSE;
234 }
235
236 if (pwct != NULL) {
237 *pwct = wct;
238 }
239 if (pvwv != NULL) {
240 *pvwv = vwv;
241 }
242 if (pnum_bytes != NULL) {
243 *pnum_bytes = num_bytes;
244 }
245 if (pbytes != NULL) {
246 *pbytes = bytes;
247 }
248
249 if (pinbuf != NULL && mem_ctx != NULL) {
250 if (talloc_reference_count(inbuf) == 0) {
251 *pinbuf = talloc_move(mem_ctx, &inbuf);
252 TALLOC_FREE(recv_iov);
253 } else {
254 *pinbuf = inbuf;
255 }
256 } else if (mem_ctx != NULL) {
257 if (talloc_reference_count(inbuf) == 0) {
258 (void)talloc_move(mem_ctx, &inbuf);
259 TALLOC_FREE(recv_iov);
260 }
261 }
262
263 return status;
264}
Note: See TracBrowser for help on using the repository browser.