9755d57254ec3457e1eafc12c81fecaf5c4293bf
[kai/samba.git] / source3 / libsmb / clitrans.c
1 /*
2    Unix SMB/CIFS implementation.
3    client transaction calls
4    Copyright (C) Andrew Tridgell 1994-1998
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_trans_state {
27         struct cli_state *cli;
28         struct tevent_req *req;
29         struct cli_trans_state **ptr;
30 };
31
32 static int cli_trans_state_destructor(struct cli_trans_state *state)
33 {
34         talloc_set_destructor(state->ptr, NULL);
35         talloc_free(state->ptr);
36         return 0;
37 }
38
39 static int cli_trans_state_ptr_destructor(struct cli_trans_state **ptr)
40 {
41         struct cli_trans_state *state = *ptr;
42         void *parent = talloc_parent(state);
43
44         talloc_set_destructor(state, NULL);
45
46         talloc_reparent(state, parent, state->req);
47         talloc_free(state);
48         return 0;
49 }
50
51 struct tevent_req *cli_trans_send(
52         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
53         struct cli_state *cli, uint8_t cmd,
54         const char *pipe_name, uint16_t fid, uint16_t function, int flags,
55         uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
56         uint8_t *param, uint32_t num_param, uint32_t max_param,
57         uint8_t *data, uint32_t num_data, uint32_t max_data)
58 {
59         struct cli_trans_state *state;
60         uint8_t additional_flags = 0;
61         uint8_t clear_flags = 0;
62         uint16_t additional_flags2 = 0;
63         uint16_t clear_flags2 = 0;
64         uint16_t tid = 0;
65
66         state = talloc_zero(mem_ctx, struct cli_trans_state);
67         if (state == NULL) {
68                 return NULL;
69         }
70         state->cli = cli;
71         state->ptr = talloc(state, struct cli_trans_state *);
72         if (state->ptr == NULL) {
73                 talloc_free(state);
74                 return NULL;
75         }
76         *state->ptr = state;
77         if (cli->case_sensitive) {
78                 clear_flags |= FLAG_CASELESS_PATHNAMES;
79         } else {
80                 /* Default setting, case insensitive. */
81                 additional_flags |= FLAG_CASELESS_PATHNAMES;
82         }
83
84         if ((smb1cli_conn_capabilities(cli->conn) & CAP_DFS) && cli->dfsroot) {
85                 additional_flags2 |= FLAGS2_DFS_PATHNAMES;
86         }
87
88         tid = cli_state_get_tid(cli);
89         state->req = smb1cli_trans_send(state, ev,
90                                         cli->conn, cmd,
91                                         additional_flags, clear_flags,
92                                         additional_flags2, clear_flags2,
93                                         cli->timeout,
94                                         cli->smb1.pid, tid,
95                                         cli->smb1.session,
96                                         pipe_name, fid, function, flags,
97                                         setup, num_setup, max_setup,
98                                         param, num_param, max_param,
99                                         data, num_data, max_data);
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_trans_state_destructor);
107         talloc_set_destructor(state->ptr, cli_trans_state_ptr_destructor);
108
109         return state->req;
110 }
111
112 NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
113                         uint16_t *recv_flags2,
114                         uint16_t **setup, uint8_t min_setup,
115                         uint8_t *num_setup,
116                         uint8_t **param, uint32_t min_param,
117                         uint32_t *num_param,
118                         uint8_t **data, uint32_t min_data,
119                         uint32_t *num_data)
120 {
121         NTSTATUS status;
122         void *parent = talloc_parent(req);
123         struct cli_trans_state *state =
124                 talloc_get_type(parent,
125                 struct cli_trans_state);
126         bool map_dos_errors = true;
127
128         status = smb1cli_trans_recv(req, mem_ctx, recv_flags2,
129                                     setup, min_setup, num_setup,
130                                     param, min_param, num_param,
131                                     data, min_data, num_data);
132
133         if (state) {
134                 map_dos_errors = state->cli->map_dos_errors;
135                 state->cli->raw_status = status;
136                 talloc_free(state->ptr);
137                 state = NULL;
138         }
139
140         if (NT_STATUS_IS_DOS(status) && map_dos_errors) {
141                 uint8_t eclass = NT_STATUS_DOS_CLASS(status);
142                 uint16_t ecode = NT_STATUS_DOS_CODE(status);
143                 /*
144                  * TODO: is it really a good idea to do a mapping here?
145                  *
146                  * The old cli_pull_error() also does it, so I do not change
147                  * the behavior yet.
148                  */
149                 status = dos_to_ntstatus(eclass, ecode);
150         }
151
152         return status;
153 }
154
155 NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
156                    uint8_t trans_cmd,
157                    const char *pipe_name, uint16_t fid, uint16_t function,
158                    int flags,
159                    uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
160                    uint8_t *param, uint32_t num_param, uint32_t max_param,
161                    uint8_t *data, uint32_t num_data, uint32_t max_data,
162                    uint16_t *recv_flags2,
163                    uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
164                    uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
165                    uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata)
166 {
167         NTSTATUS status;
168         uint8_t additional_flags = 0;
169         uint8_t clear_flags = 0;
170         uint16_t additional_flags2 = 0;
171         uint16_t clear_flags2 = 0;
172         uint16_t tid = 0;
173
174         if (cli->case_sensitive) {
175                 clear_flags |= FLAG_CASELESS_PATHNAMES;
176         } else {
177                 /* Default setting, case insensitive. */
178                 additional_flags |= FLAG_CASELESS_PATHNAMES;
179         }
180
181         if ((smb1cli_conn_capabilities(cli->conn) & CAP_DFS) && cli->dfsroot) {
182                 additional_flags2 |= FLAGS2_DFS_PATHNAMES;
183         }
184
185         tid = cli_state_get_tid(cli);
186         status = smb1cli_trans(mem_ctx,
187                                cli->conn, trans_cmd,
188                                additional_flags, clear_flags,
189                                additional_flags2, clear_flags2,
190                                cli->timeout,
191                                cli->smb1.pid, tid,
192                                cli->smb1.session,
193                                pipe_name, fid, function, flags,
194                                setup, num_setup, max_setup,
195                                param, num_param, max_param,
196                                data, num_data, max_data,
197                                recv_flags2,
198                                rsetup, min_rsetup, num_rsetup,
199                                rparam, min_rparam, num_rparam,
200                                rdata, min_rdata, num_rdata);
201
202         cli->raw_status = status;
203
204         if (NT_STATUS_IS_DOS(status) && cli->map_dos_errors) {
205                 uint8_t eclass = NT_STATUS_DOS_CLASS(status);
206                 uint16_t ecode = NT_STATUS_DOS_CODE(status);
207                 /*
208                  * TODO: is it really a good idea to do a mapping here?
209                  *
210                  * The old cli_pull_error() also does it, so I do not change
211                  * the behavior yet.
212                  */
213                 status = dos_to_ntstatus(eclass, ecode);
214         }
215
216         return status;
217 }