]> git.samba.org - mat/samba.git/blob - source3/libsmb/async_smb.c
s3:libsmb: use cli_state_{g,s}et_uid instead of smb1.uid directly
[mat/samba.git] / source3 / libsmb / async_smb.c
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 static 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
40 static 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
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)
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         uint16_t uid = 0;
66
67         state = talloc_zero(mem_ctx, struct cli_smb_req_state);
68         if (state == NULL) {
69                 return NULL;
70         }
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;
77         }
78         *state->ptr = state;
79
80         if (cli->case_sensitive) {
81                 clear_flags |= FLAG_CASELESS_PATHNAMES;
82         } else {
83                 /* Default setting, case insensitive. */
84                 additional_flags |= FLAG_CASELESS_PATHNAMES;
85         }
86
87         if ((smb1cli_conn_capabilities(cli->conn) & CAP_DFS) && cli->dfsroot) {
88                 additional_flags2 |= FLAGS2_DFS_PATHNAMES;
89         }
90
91         uid = cli_state_get_uid(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                                         cli->smb1.tid,
98                                         uid,
99                                         wct, vwv, iov_count, bytes_iov);
100         if (state->req == NULL) {
101                 talloc_free(state);
102                 return NULL;
103         }
104
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);
108
109         return state->req;
110 }
111
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)
120 {
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 uid = 0;
126
127         state = talloc_zero(mem_ctx, struct cli_smb_req_state);
128         if (state == NULL) {
129                 return NULL;
130         }
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;
137         }
138         *state->ptr = state;
139
140         if (cli->case_sensitive) {
141                 clear_flags |= FLAG_CASELESS_PATHNAMES;
142         } else {
143                 /* Default setting, case insensitive. */
144                 additional_flags |= FLAG_CASELESS_PATHNAMES;
145         }
146
147         if ((smb1cli_conn_capabilities(cli->conn) & CAP_DFS) && cli->dfsroot) {
148                 additional_flags2 |= FLAGS2_DFS_PATHNAMES;
149         }
150
151         uid = cli_state_get_uid(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                                 cli->smb1.tid,
158                                 uid,
159                                 wct, vwv, num_bytes, bytes);
160         if (state->req == NULL) {
161                 talloc_free(state);
162                 return NULL;
163         }
164
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);
168
169         return state->req;
170 }
171
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)
176 {
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;
190
191         if (pinbuf != NULL) {
192                 *pinbuf = NULL;
193         }
194         if (pwct != NULL) {
195                 *pwct = 0;
196         }
197         if (pvwv != NULL) {
198                 *pvwv = NULL;
199         }
200         if (pnum_bytes != NULL) {
201                 *pnum_bytes = 0;
202         }
203         if (pbytes != NULL) {
204                 *pbytes = NULL;
205         }
206
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 */
218
219         if (state) {
220                 if ((state->smb_command == SMBsesssetupX) &&
221                      NT_STATUS_EQUAL(status,
222                                 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
223                         /*
224                          * NT_STATUS_MORE_PROCESSING_REQUIRED is a
225                          * valid return code for session setup
226                          */
227                         is_expected = true;
228                 }
229
230                 map_dos_errors = state->cli->map_dos_errors;
231                 state->cli->raw_status = status;
232                 talloc_free(state->ptr);
233                 state = NULL;
234         }
235
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);
239                 /*
240                  * TODO: is it really a good idea to do a mapping here?
241                  *
242                  * The old cli_pull_error() also does it, so I do not change
243                  * the behavior yet.
244                  */
245                 status = dos_to_ntstatus(eclass, ecode);
246         }
247
248         if (!NT_STATUS_IS_ERR(status)) {
249                 is_expected = true;
250         }
251
252         if (!is_expected) {
253                 TALLOC_FREE(recv_iov);
254                 return status;
255         }
256
257         if (wct < min_wct) {
258                 TALLOC_FREE(recv_iov);
259                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
260         }
261
262         if (pwct != NULL) {
263                 *pwct = wct;
264         }
265         if (pvwv != NULL) {
266                 *pvwv = vwv;
267         }
268         if (pnum_bytes != NULL) {
269                 *pnum_bytes = num_bytes;
270         }
271         if (pbytes != NULL) {
272                 *pbytes = bytes;
273         }
274
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;
281                 }
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);
286                 }
287         }
288
289         return status;
290 }