s4:libcli/raw: implement on top of smbXcli_conn/req
[kai/samba.git] / source4 / libcli / raw / rawtrans.c
1 /* 
2    Unix SMB/CIFS implementation.
3    raw trans/trans2/nttrans operations
4
5    Copyright (C) James Myers 2003 <myersjj@samba.org>
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include <tevent.h>
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "../libcli/smb/smbXcli_base.h"
26
27 static void smb_raw_trans_backend_done(struct tevent_req *subreq);
28
29 static struct smbcli_request *smb_raw_trans_backend_send(struct smbcli_tree *tree,
30                                                          struct smb_trans2 *parms,
31                                                          uint8_t command)
32 {
33         struct smbcli_request *req;
34         uint8_t additional_flags;
35         uint8_t clear_flags;
36         uint16_t additional_flags2;
37         uint16_t clear_flags2;
38         uint32_t pid;
39         uint16_t tid;
40         uint16_t uid;
41         const char *pipe_name = NULL;
42         uint8_t s;
43         uint32_t timeout_msec;
44         uint32_t tmp;
45
46         tmp = parms->in.params.length + parms->in.data.length;
47
48         req = smbcli_request_setup(tree, command, parms->in.setup_count, tmp);
49         if (req == NULL) {
50                 return NULL;
51         }
52
53         additional_flags = CVAL(req->out.hdr, HDR_FLG);
54         additional_flags2 = SVAL(req->out.hdr, HDR_FLG2);
55         pid  = SVAL(req->out.hdr, HDR_PID);
56         pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16;
57         tid = SVAL(req->out.hdr, HDR_TID);
58         uid = SVAL(req->out.hdr, HDR_UID);
59
60         clear_flags = ~additional_flags;
61         clear_flags2 = ~additional_flags2;
62
63         timeout_msec = req->transport->options.request_timeout * 1000;
64
65         for (s=0; s < parms->in.setup_count; s++) {
66                 SSVAL(req->out.vwv, VWV(s), parms->in.setup[s]);
67         }
68
69         memcpy(req->out.data,
70                parms->in.params.data,
71                parms->in.params.length);
72         memcpy(req->out.data + parms->in.params.length,
73                parms->in.data.data,
74                parms->in.data.length);
75
76         if (command == SMBtrans && parms->in.trans_name) {
77                 pipe_name = parms->in.trans_name;
78         }
79
80         req->subreqs[0] = smb1cli_trans_send(req,
81                                              req->transport->ev,
82                                              req->transport->conn,
83                                              command,
84                                              additional_flags,
85                                              clear_flags,
86                                              additional_flags2,
87                                              clear_flags2,
88                                              timeout_msec,
89                                              pid, tid, uid,
90                                              pipe_name,
91                                              0xFFFF, /* fid */
92                                              0, /* function */
93                                              parms->in.flags,
94                                              (uint16_t *)req->out.vwv,
95                                              parms->in.setup_count,
96                                              parms->in.max_setup,
97                                              req->out.data,
98                                              parms->in.params.length,
99                                              parms->in.max_param,
100                                              req->out.data+
101                                              parms->in.params.length,
102                                              parms->in.data.length,
103                                              parms->in.max_data);
104         if (req->subreqs[0] == NULL) {
105                 talloc_free(req);
106                 return NULL;
107         }
108         tevent_req_set_callback(req->subreqs[0],
109                                 smb_raw_trans_backend_done,
110                                 req);
111
112         return req;
113 }
114
115 static void smb_raw_trans_backend_done(struct tevent_req *subreq)
116 {
117         struct smbcli_request *req =
118                 tevent_req_callback_data(subreq,
119                 struct smbcli_request);
120         struct smbcli_transport *transport = req->transport;
121         uint16_t *setup = NULL;
122         uint8_t num_setup = 0;
123         uint8_t s;
124         uint8_t *param = NULL;
125         uint32_t num_param = 0;
126         uint8_t *data = NULL;
127         uint32_t num_data = 0;
128
129         req->status = smb1cli_trans_recv(req->subreqs[0], req,
130                                          &req->flags2,
131                                          &setup,
132                                          0, /* min_setup */
133                                          &num_setup,
134                                          &param,
135                                          0, /* min_param */
136                                          &num_param,
137                                          &data,
138                                          0, /* min_data */
139                                          &num_data);
140         TALLOC_FREE(req->subreqs[0]);
141         if (NT_STATUS_IS_ERR(req->status)) {
142                 req->state = SMBCLI_REQUEST_ERROR;
143                 transport->error.e.nt_status = req->status;
144                 transport->error.etype = ETYPE_SMB;
145                 if (req->async.fn) {
146                         req->async.fn(req);
147                 }
148                 return;
149         }
150
151         req->trans2.out.setup_count = num_setup;
152         req->trans2.out.setup = talloc_array(req, uint16_t, num_setup);
153         if (req->trans2.out.setup == NULL) {
154                 req->state = SMBCLI_REQUEST_ERROR;
155                 req->status = NT_STATUS_NO_MEMORY;
156                 transport->error.e.nt_status = req->status;
157                 transport->error.etype = ETYPE_SMB;
158                 if (req->async.fn) {
159                         req->async.fn(req);
160                 }
161                 return;
162         }
163         for (s = 0; s < num_setup; s++) {
164                 req->trans2.out.setup[s] = SVAL(setup, VWV(s));
165         }
166
167         req->trans2.out.params.data = param;
168         req->trans2.out.params.length = num_param;
169
170         req->trans2.out.data.data = data;
171         req->trans2.out.data.length = num_data;
172
173         transport->error.e.nt_status = req->status;
174         if (NT_STATUS_IS_OK(req->status)) {
175                 transport->error.etype = ETYPE_NONE;
176         } else {
177                 transport->error.etype = ETYPE_SMB;
178         }
179
180         req->state = SMBCLI_REQUEST_DONE;
181         if (req->async.fn) {
182                 req->async.fn(req);
183         }
184 }
185
186 static NTSTATUS smb_raw_trans_backend_recv(struct smbcli_request *req,
187                                            TALLOC_CTX *mem_ctx,
188                                            struct smb_trans2 *parms)
189 {
190         if (!smbcli_request_receive(req) ||
191             smbcli_request_is_error(req)) {
192                 goto failed;
193         }
194
195         parms->out = req->trans2.out;
196         talloc_steal(mem_ctx, parms->out.setup);
197         talloc_steal(mem_ctx, parms->out.params.data);
198         talloc_steal(mem_ctx, parms->out.data.data);
199
200 failed:
201         return smbcli_request_destroy(req);
202 }
203
204 _PUBLIC_ struct smbcli_request *smb_raw_trans_send(struct smbcli_tree *tree,
205                                        struct smb_trans2 *parms)
206 {
207         return smb_raw_trans_backend_send(tree, parms, SMBtrans);
208 }
209
210 _PUBLIC_ NTSTATUS smb_raw_trans_recv(struct smbcli_request *req,
211                              TALLOC_CTX *mem_ctx,
212                              struct smb_trans2 *parms)
213 {
214         return smb_raw_trans_backend_recv(req, mem_ctx, parms);
215 }
216
217 _PUBLIC_ NTSTATUS smb_raw_trans(struct smbcli_tree *tree,
218                        TALLOC_CTX *mem_ctx,
219                        struct smb_trans2 *parms)
220 {
221         struct smbcli_request *req;
222         req = smb_raw_trans_send(tree, parms);
223         if (!req) return NT_STATUS_UNSUCCESSFUL;
224         return smb_raw_trans_recv(req, mem_ctx, parms);
225 }
226
227 struct smbcli_request *smb_raw_trans2_send(struct smbcli_tree *tree,
228                                        struct smb_trans2 *parms)
229 {
230         return smb_raw_trans_backend_send(tree, parms, SMBtrans2);
231 }
232
233 NTSTATUS smb_raw_trans2_recv(struct smbcli_request *req,
234                              TALLOC_CTX *mem_ctx,
235                              struct smb_trans2 *parms)
236 {
237         return smb_raw_trans_backend_recv(req, mem_ctx, parms);
238 }
239
240 NTSTATUS smb_raw_trans2(struct smbcli_tree *tree,
241                         TALLOC_CTX *mem_ctx,
242                         struct smb_trans2 *parms)
243 {
244         struct smbcli_request *req;
245         req = smb_raw_trans2_send(tree, parms);
246         if (!req) return NT_STATUS_UNSUCCESSFUL;
247         return smb_raw_trans2_recv(req, mem_ctx, parms);
248 }
249
250 static void smb_raw_nttrans_done(struct tevent_req *subreq);
251
252 struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
253                                             struct smb_nttrans *parms)
254 {
255         struct smbcli_request *req;
256         uint8_t additional_flags;
257         uint8_t clear_flags;
258         uint16_t additional_flags2;
259         uint16_t clear_flags2;
260         uint32_t pid;
261         uint16_t tid;
262         uint16_t uid;
263         uint32_t timeout_msec;
264         uint32_t tmp;
265
266         tmp = parms->in.params.length + parms->in.data.length;
267
268         req = smbcli_request_setup(tree, SMBnttrans, parms->in.setup_count, tmp);
269         if (req == NULL) {
270                 return NULL;
271         }
272
273         additional_flags = CVAL(req->out.hdr, HDR_FLG);
274         additional_flags2 = SVAL(req->out.hdr, HDR_FLG2);
275         pid  = SVAL(req->out.hdr, HDR_PID);
276         pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16;
277         tid = SVAL(req->out.hdr, HDR_TID);
278         uid = SVAL(req->out.hdr, HDR_UID);
279
280         clear_flags = ~additional_flags;
281         clear_flags2 = ~additional_flags2;
282
283         timeout_msec = req->transport->options.request_timeout * 1000;
284
285         memcpy(req->out.vwv,
286                parms->in.setup,
287                parms->in.setup_count * 2);
288
289         memcpy(req->out.data,
290                parms->in.params.data,
291                parms->in.params.length);
292         memcpy(req->out.data + parms->in.params.length,
293                parms->in.data.data,
294                parms->in.data.length);
295
296         req->subreqs[0] = smb1cli_trans_send(req,
297                                              req->transport->ev,
298                                              req->transport->conn,
299                                              SMBnttrans,
300                                              additional_flags,
301                                              clear_flags,
302                                              additional_flags2,
303                                              clear_flags2,
304                                              timeout_msec,
305                                              pid, tid, uid,
306                                              NULL, /* pipe_name */
307                                              0xFFFF, /* fid */
308                                              parms->in.function,
309                                              0, /* flags */
310                                              (uint16_t *)req->out.vwv,
311                                              parms->in.setup_count,
312                                              parms->in.max_setup,
313                                              req->out.data,
314                                              parms->in.params.length,
315                                              parms->in.max_param,
316                                              req->out.data+
317                                              parms->in.params.length,
318                                              parms->in.data.length,
319                                              parms->in.max_data);
320         if (req->subreqs[0] == NULL) {
321                 talloc_free(req);
322                 return NULL;
323         }
324         tevent_req_set_callback(req->subreqs[0],
325                                 smb_raw_nttrans_done,
326                                 req);
327
328         return req;
329 }
330
331 static void smb_raw_nttrans_done(struct tevent_req *subreq)
332 {
333         struct smbcli_request *req =
334                 tevent_req_callback_data(subreq,
335                 struct smbcli_request);
336         struct smbcli_transport *transport = req->transport;
337         uint16_t *setup = NULL;
338         uint8_t num_setup = 0;
339         uint8_t *param = NULL;
340         uint32_t num_param = 0;
341         uint8_t *data = NULL;
342         uint32_t num_data = 0;
343
344         req->status = smb1cli_trans_recv(req->subreqs[0], req,
345                                          &req->flags2,
346                                          &setup,
347                                          0, /* min_setup */
348                                          &num_setup,
349                                          &param,
350                                          0, /* min_param */
351                                          &num_param,
352                                          &data,
353                                          0, /* min_data */
354                                          &num_data);
355         TALLOC_FREE(req->subreqs[0]);
356         if (NT_STATUS_IS_ERR(req->status)) {
357                 req->state = SMBCLI_REQUEST_ERROR;
358                 transport->error.e.nt_status = req->status;
359                 transport->error.etype = ETYPE_SMB;
360                 if (req->async.fn) {
361                         req->async.fn(req);
362                 }
363                 return;
364         }
365
366         req->nttrans.out.setup_count = num_setup;
367         req->nttrans.out.setup = (uint8_t *)setup;
368
369         req->nttrans.out.params.data = param;
370         req->nttrans.out.params.length = num_param;
371
372         req->nttrans.out.data.data = data;
373         req->nttrans.out.data.length = num_data;
374
375         transport->error.e.nt_status = req->status;
376         if (NT_STATUS_IS_OK(req->status)) {
377                 transport->error.etype = ETYPE_NONE;
378         } else {
379                 transport->error.etype = ETYPE_SMB;
380         }
381
382         req->state = SMBCLI_REQUEST_DONE;
383         if (req->async.fn) {
384                 req->async.fn(req);
385         }
386 }
387
388 NTSTATUS smb_raw_nttrans_recv(struct smbcli_request *req,
389                               TALLOC_CTX *mem_ctx,
390                               struct smb_nttrans *parms)
391 {
392         if (!smbcli_request_receive(req) ||
393             smbcli_request_is_error(req)) {
394                 goto failed;
395         }
396
397         parms->out = req->nttrans.out;
398         talloc_steal(mem_ctx, parms->out.setup);
399         talloc_steal(mem_ctx, parms->out.params.data);
400         talloc_steal(mem_ctx, parms->out.data.data);
401
402 failed:
403         return smbcli_request_destroy(req);
404 }
405
406 /****************************************************************************
407   receive a SMB nttrans response allocating the necessary memory
408   ****************************************************************************/
409 NTSTATUS smb_raw_nttrans(struct smbcli_tree *tree,
410                          TALLOC_CTX *mem_ctx,
411                          struct smb_nttrans *parms)
412 {
413         struct smbcli_request *req;
414
415         req = smb_raw_nttrans_send(tree, parms);
416         if (!req) {
417                 return NT_STATUS_UNSUCCESSFUL;
418         }
419
420         return smb_raw_nttrans_recv(req, mem_ctx, parms);
421 }