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 68936 : static int cli_smb_req_state_ptr_destructor(struct cli_smb_req_state **ptr)
41 : {
42 68936 : struct cli_smb_req_state *state = *ptr;
43 68936 : void *parent = talloc_parent(state);
44 :
45 68936 : talloc_set_destructor(state, NULL);
46 :
47 68936 : talloc_reparent(state, parent, state->req);
48 68936 : talloc_free(state);
49 68936 : return 0;
50 : }
51 :
52 2997 : 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 : struct cli_smb_req_state *state;
63 2997 : uint8_t clear_flags = 0;
64 2997 : uint16_t clear_flags2 = 0;
65 :
66 2997 : state = talloc_zero(mem_ctx, struct cli_smb_req_state);
67 2997 : if (state == NULL) {
68 0 : return NULL;
69 : }
70 2997 : state->cli = cli;
71 2997 : state->smb_command = smb_command;
72 2997 : state->ptr = talloc(state, struct cli_smb_req_state *);
73 2997 : if (state->ptr == NULL) {
74 0 : talloc_free(state);
75 0 : return NULL;
76 : }
77 2997 : *state->ptr = state;
78 :
79 5994 : state->req = smb1cli_req_create(state, ev, cli->conn, smb_command,
80 : additional_flags, clear_flags,
81 : additional_flags2, clear_flags2,
82 2997 : cli->timeout,
83 : cli->smb1.pid,
84 : cli->smb1.tcon,
85 : cli->smb1.session,
86 : wct, vwv, iov_count, bytes_iov);
87 2997 : if (state->req == NULL) {
88 0 : talloc_free(state);
89 0 : return NULL;
90 : }
91 :
92 2997 : talloc_reparent(state, state->req, state->ptr);
93 2997 : talloc_set_destructor(state, cli_smb_req_state_destructor);
94 2997 : talloc_set_destructor(state->ptr, cli_smb_req_state_ptr_destructor);
95 :
96 2997 : return state->req;
97 : }
98 :
99 65939 : 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 : struct cli_smb_req_state *state;
110 65939 : uint8_t clear_flags = 0;
111 65939 : uint16_t clear_flags2 = 0;
112 :
113 65939 : state = talloc_zero(mem_ctx, struct cli_smb_req_state);
114 65939 : if (state == NULL) {
115 0 : return NULL;
116 : }
117 65939 : state->cli = cli;
118 65939 : state->smb_command = smb_command;
119 65939 : state->ptr = talloc(state, struct cli_smb_req_state *);
120 65939 : if (state->ptr == NULL) {
121 0 : talloc_free(state);
122 0 : return NULL;
123 : }
124 65939 : *state->ptr = state;
125 :
126 131878 : state->req = smb1cli_req_send(state, ev, cli->conn, smb_command,
127 : additional_flags, clear_flags,
128 : additional_flags2, clear_flags2,
129 65939 : cli->timeout,
130 : cli->smb1.pid,
131 : cli->smb1.tcon,
132 : cli->smb1.session,
133 : wct, vwv, num_bytes, bytes);
134 65939 : if (state->req == NULL) {
135 0 : talloc_free(state);
136 0 : return NULL;
137 : }
138 :
139 65939 : talloc_reparent(state, state->req, state->ptr);
140 65939 : talloc_set_destructor(state, cli_smb_req_state_destructor);
141 65939 : talloc_set_destructor(state->ptr, cli_smb_req_state_ptr_destructor);
142 :
143 65939 : return state->req;
144 : }
145 :
146 68936 : 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 : NTSTATUS status;
152 68936 : void *parent = talloc_parent(req);
153 68914 : struct cli_smb_req_state *state =
154 22 : talloc_get_type(parent,
155 : struct cli_smb_req_state);
156 68936 : struct iovec *recv_iov = NULL;
157 68936 : uint8_t wct = 0;
158 68936 : uint16_t *vwv = NULL;
159 : uint32_t num_bytes;
160 68936 : uint8_t *bytes = NULL;
161 : uint8_t *inbuf;
162 68936 : bool is_expected = false;
163 68936 : bool map_dos_errors = true;
164 :
165 68936 : if (pinbuf != NULL) {
166 460 : *pinbuf = NULL;
167 : }
168 68936 : if (pwct != NULL) {
169 1975 : *pwct = 0;
170 : }
171 68936 : if (pvwv != NULL) {
172 1985 : *pvwv = NULL;
173 : }
174 68936 : if (pnum_bytes != NULL) {
175 526 : *pnum_bytes = 0;
176 : }
177 68936 : if (pbytes != NULL) {
178 526 : *pbytes = NULL;
179 : }
180 :
181 68936 : 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 68936 : if (state) {
194 68937 : if ((state->smb_command == SMBsesssetupX) &&
195 1 : 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 68936 : map_dos_errors = state->cli->map_dos_errors;
205 68936 : state->cli->raw_status = status;
206 68936 : talloc_free(state->ptr);
207 68936 : state = NULL;
208 : }
209 :
210 68936 : if (NT_STATUS_IS_DOS(status) && map_dos_errors) {
211 65543 : uint8_t eclass = NT_STATUS_DOS_CLASS(status);
212 65543 : 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 65543 : status = dos_to_ntstatus(eclass, ecode);
220 : }
221 :
222 68936 : if (!NT_STATUS_IS_ERR(status)) {
223 2851 : is_expected = true;
224 : }
225 :
226 68936 : if (!is_expected) {
227 66085 : TALLOC_FREE(recv_iov);
228 66085 : return status;
229 : }
230 :
231 2851 : if (wct < min_wct) {
232 0 : TALLOC_FREE(recv_iov);
233 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
234 : }
235 :
236 2851 : if (pwct != NULL) {
237 1926 : *pwct = wct;
238 : }
239 2851 : if (pvwv != NULL) {
240 1935 : *pvwv = vwv;
241 : }
242 2851 : if (pnum_bytes != NULL) {
243 503 : *pnum_bytes = num_bytes;
244 : }
245 2851 : if (pbytes != NULL) {
246 503 : *pbytes = bytes;
247 : }
248 :
249 2851 : if (pinbuf != NULL && mem_ctx != NULL) {
250 887 : if (talloc_reference_count(inbuf) == 0) {
251 447 : *pinbuf = talloc_move(mem_ctx, &inbuf);
252 447 : TALLOC_FREE(recv_iov);
253 : } else {
254 1 : *pinbuf = inbuf;
255 : }
256 2403 : } else if (mem_ctx != NULL) {
257 1478 : if (talloc_reference_count(inbuf) == 0) {
258 1474 : (void)talloc_move(mem_ctx, &inbuf);
259 1474 : TALLOC_FREE(recv_iov);
260 : }
261 : }
262 :
263 2851 : return status;
264 : }
|