Line data Source code
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 :
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;
31 : };
32 :
33 0 : static int cli_smb_req_state_destructor(struct cli_smb_req_state *state)
34 : {
35 0 : talloc_set_destructor(state->ptr, NULL);
36 0 : talloc_free(state->ptr);
37 0 : return 0;
38 : }
39 :
40 379936 : static int cli_smb_req_state_ptr_destructor(struct cli_smb_req_state **ptr)
41 : {
42 379936 : struct cli_smb_req_state *state = *ptr;
43 379936 : void *parent = talloc_parent(state);
44 :
45 379936 : talloc_set_destructor(state, NULL);
46 :
47 379936 : talloc_reparent(state, parent, state->req);
48 379936 : talloc_free(state);
49 379936 : return 0;
50 : }
51 :
52 35763 : 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 : uint16_t additional_flags2,
58 : uint8_t wct, uint16_t *vwv,
59 : int iov_count,
60 : struct iovec *bytes_iov)
61 : {
62 0 : struct cli_smb_req_state *state;
63 35763 : uint8_t clear_flags = 0;
64 35763 : uint16_t clear_flags2 = 0;
65 :
66 35763 : state = talloc_zero(mem_ctx, struct cli_smb_req_state);
67 35763 : if (state == NULL) {
68 0 : return NULL;
69 : }
70 35763 : state->cli = cli;
71 35763 : state->smb_command = smb_command;
72 35763 : state->ptr = talloc(state, struct cli_smb_req_state *);
73 35763 : if (state->ptr == NULL) {
74 0 : talloc_free(state);
75 0 : return NULL;
76 : }
77 35763 : *state->ptr = state;
78 :
79 71526 : state->req = smb1cli_req_create(state, ev, cli->conn, smb_command,
80 : additional_flags, clear_flags,
81 : additional_flags2, clear_flags2,
82 35763 : cli->timeout,
83 : cli->smb1.pid,
84 : cli->smb1.tcon,
85 : cli->smb1.session,
86 : wct, vwv, iov_count, bytes_iov);
87 35763 : if (state->req == NULL) {
88 0 : talloc_free(state);
89 0 : return NULL;
90 : }
91 :
92 35763 : talloc_reparent(state, state->req, state->ptr);
93 35763 : talloc_set_destructor(state, cli_smb_req_state_destructor);
94 35763 : talloc_set_destructor(state->ptr, cli_smb_req_state_ptr_destructor);
95 :
96 35763 : return state->req;
97 : }
98 :
99 344173 : struct 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 : uint16_t additional_flags2,
105 : uint8_t wct, uint16_t *vwv,
106 : uint32_t num_bytes,
107 : const uint8_t *bytes)
108 : {
109 0 : struct cli_smb_req_state *state;
110 344173 : uint8_t clear_flags = 0;
111 344173 : uint16_t clear_flags2 = 0;
112 :
113 344173 : state = talloc_zero(mem_ctx, struct cli_smb_req_state);
114 344173 : if (state == NULL) {
115 0 : return NULL;
116 : }
117 344173 : state->cli = cli;
118 344173 : state->smb_command = smb_command;
119 344173 : state->ptr = talloc(state, struct cli_smb_req_state *);
120 344173 : if (state->ptr == NULL) {
121 0 : talloc_free(state);
122 0 : return NULL;
123 : }
124 344173 : *state->ptr = state;
125 :
126 688346 : state->req = smb1cli_req_send(state, ev, cli->conn, smb_command,
127 : additional_flags, clear_flags,
128 : additional_flags2, clear_flags2,
129 344173 : cli->timeout,
130 : cli->smb1.pid,
131 : cli->smb1.tcon,
132 : cli->smb1.session,
133 : wct, vwv, num_bytes, bytes);
134 344173 : if (state->req == NULL) {
135 0 : talloc_free(state);
136 0 : return NULL;
137 : }
138 :
139 344173 : talloc_reparent(state, state->req, state->ptr);
140 344173 : talloc_set_destructor(state, cli_smb_req_state_destructor);
141 344173 : talloc_set_destructor(state->ptr, cli_smb_req_state_ptr_destructor);
142 :
143 344173 : return state->req;
144 : }
145 :
146 379936 : NTSTATUS 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 0 : NTSTATUS status;
152 379936 : void *parent = talloc_parent(req);
153 0 : struct cli_smb_req_state *state =
154 379936 : talloc_get_type(parent,
155 : struct cli_smb_req_state);
156 379936 : struct iovec *recv_iov = NULL;
157 379936 : uint8_t wct = 0;
158 379936 : uint16_t *vwv = NULL;
159 0 : uint32_t num_bytes;
160 379936 : uint8_t *bytes = NULL;
161 0 : uint8_t *inbuf;
162 379936 : bool is_expected = false;
163 379936 : bool map_dos_errors = true;
164 :
165 379936 : if (pinbuf != NULL) {
166 14667 : *pinbuf = NULL;
167 : }
168 379936 : if (pwct != NULL) {
169 31921 : *pwct = 0;
170 : }
171 379936 : if (pvwv != NULL) {
172 32037 : *pvwv = NULL;
173 : }
174 379936 : if (pnum_bytes != NULL) {
175 18541 : *pnum_bytes = 0;
176 : }
177 379936 : if (pbytes != NULL) {
178 18541 : *pbytes = NULL;
179 : }
180 :
181 379936 : 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 379936 : if (state) {
194 379936 : if ((state->smb_command == SMBsesssetupX) &&
195 5 : 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 0 : is_expected = true;
202 : }
203 :
204 379936 : if ((state->smb_command == SMBntcreateX) &&
205 3863 : NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
206 0 : min_wct = 0;
207 : }
208 :
209 379936 : map_dos_errors = state->cli->map_dos_errors;
210 379936 : state->cli->raw_status = status;
211 379936 : talloc_free(state->ptr);
212 379936 : state = NULL;
213 : }
214 :
215 379936 : if (NT_STATUS_IS_DOS(status) && map_dos_errors) {
216 327721 : uint8_t eclass = NT_STATUS_DOS_CLASS(status);
217 327721 : uint16_t ecode = NT_STATUS_DOS_CODE(status);
218 : /*
219 : * TODO: is it really a good idea to do a mapping here?
220 : *
221 : * The old cli_pull_error() also does it, so I do not change
222 : * the behavior yet.
223 : */
224 327721 : status = dos_to_ntstatus(eclass, ecode);
225 : }
226 :
227 379936 : if (!NT_STATUS_IS_ERR(status)) {
228 48508 : is_expected = true;
229 : }
230 :
231 379936 : if (!is_expected) {
232 331428 : TALLOC_FREE(recv_iov);
233 331428 : return status;
234 : }
235 :
236 48508 : if (wct < min_wct) {
237 0 : TALLOC_FREE(recv_iov);
238 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
239 : }
240 :
241 48508 : if (pwct != NULL) {
242 31231 : *pwct = wct;
243 : }
244 48508 : if (pvwv != NULL) {
245 31340 : *pvwv = vwv;
246 : }
247 48508 : if (pnum_bytes != NULL) {
248 17981 : *pnum_bytes = num_bytes;
249 : }
250 48508 : if (pbytes != NULL) {
251 17981 : *pbytes = bytes;
252 : }
253 :
254 48508 : if (pinbuf != NULL && mem_ctx != NULL) {
255 14614 : if (talloc_reference_count(inbuf) == 0) {
256 14592 : *pinbuf = talloc_move(mem_ctx, &inbuf);
257 14592 : TALLOC_FREE(recv_iov);
258 : } else {
259 5 : *pinbuf = inbuf;
260 : }
261 33911 : } else if (mem_ctx != NULL) {
262 16632 : if (talloc_reference_count(inbuf) == 0) {
263 16612 : (void)talloc_move(mem_ctx, &inbuf);
264 16612 : TALLOC_FREE(recv_iov);
265 : }
266 : }
267 :
268 48508 : return status;
269 : }
|