/src/samba/source3/libsmb/clitrans.c
Line | Count | Source (jump to first uncovered line) |
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 "source3/include/client.h" |
22 | | #include "source3/libsmb/proto.h" |
23 | | #include "../lib/util/tevent_ntstatus.h" |
24 | | #include "async_smb.h" |
25 | | #include "../libcli/smb/smbXcli_base.h" |
26 | | |
27 | | struct cli_trans_state { |
28 | | struct cli_state *cli; |
29 | | struct tevent_req *subreq; |
30 | | uint16_t recv_flags2; |
31 | | uint16_t *setup; |
32 | | uint8_t num_setup; |
33 | | uint8_t *param; |
34 | | uint32_t num_param; |
35 | | uint8_t *data; |
36 | | uint32_t num_data; |
37 | | }; |
38 | | |
39 | | static void cli_trans_done(struct tevent_req *subreq); |
40 | | static bool cli_trans_cancel(struct tevent_req *req); |
41 | | |
42 | | struct tevent_req *cli_trans_send( |
43 | | TALLOC_CTX *mem_ctx, struct tevent_context *ev, |
44 | | struct cli_state *cli, uint16_t additional_flags2, uint8_t cmd, |
45 | | const char *pipe_name, uint16_t fid, uint16_t function, int flags, |
46 | | uint16_t *setup, uint8_t num_setup, uint8_t max_setup, |
47 | | uint8_t *param, uint32_t num_param, uint32_t max_param, |
48 | | uint8_t *data, uint32_t num_data, uint32_t max_data) |
49 | 0 | { |
50 | 0 | struct tevent_req *req; |
51 | 0 | struct cli_trans_state *state; |
52 | 0 | uint8_t additional_flags = 0; |
53 | 0 | uint8_t clear_flags = 0; |
54 | 0 | uint16_t clear_flags2 = 0; |
55 | |
|
56 | 0 | req = tevent_req_create(mem_ctx, &state, struct cli_trans_state); |
57 | 0 | if (req == NULL) { |
58 | 0 | return NULL; |
59 | 0 | } |
60 | 0 | state->cli = cli; |
61 | |
|
62 | 0 | state->subreq = smb1cli_trans_send(state, ev, |
63 | 0 | cli->conn, cmd, |
64 | 0 | additional_flags, clear_flags, |
65 | 0 | additional_flags2, clear_flags2, |
66 | 0 | cli->timeout, |
67 | 0 | cli->smb1.pid, |
68 | 0 | cli->smb1.tcon, |
69 | 0 | cli->smb1.session, |
70 | 0 | pipe_name, fid, function, flags, |
71 | 0 | setup, num_setup, max_setup, |
72 | 0 | param, num_param, max_param, |
73 | 0 | data, num_data, max_data); |
74 | 0 | if (tevent_req_nomem(state->subreq, req)) { |
75 | 0 | return tevent_req_post(req, ev); |
76 | 0 | } |
77 | 0 | tevent_req_set_callback(state->subreq, cli_trans_done, req); |
78 | 0 | tevent_req_set_cancel_fn(req, cli_trans_cancel); |
79 | 0 | return req; |
80 | 0 | } |
81 | | |
82 | | static bool cli_trans_cancel(struct tevent_req *req) |
83 | 0 | { |
84 | 0 | struct cli_trans_state *state = tevent_req_data( |
85 | 0 | req, struct cli_trans_state); |
86 | 0 | bool ok; |
87 | |
|
88 | 0 | ok = tevent_req_cancel(state->subreq); |
89 | 0 | return ok; |
90 | 0 | } |
91 | | |
92 | | static void cli_trans_done(struct tevent_req *subreq) |
93 | 0 | { |
94 | 0 | struct tevent_req *req = tevent_req_callback_data( |
95 | 0 | subreq, struct tevent_req); |
96 | 0 | struct cli_trans_state *state = tevent_req_data( |
97 | 0 | req, struct cli_trans_state); |
98 | 0 | NTSTATUS status; |
99 | |
|
100 | 0 | status = smb1cli_trans_recv( |
101 | 0 | subreq, |
102 | 0 | state, |
103 | 0 | &state->recv_flags2, |
104 | 0 | &state->setup, 0, &state->num_setup, |
105 | 0 | &state->param, 0, &state->num_param, |
106 | 0 | &state->data, 0, &state->num_data); |
107 | 0 | TALLOC_FREE(subreq); |
108 | 0 | if (tevent_req_nterror(req, status)) { |
109 | 0 | return; |
110 | 0 | } |
111 | 0 | tevent_req_done(req); |
112 | 0 | } |
113 | | |
114 | | NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, |
115 | | uint16_t *recv_flags2, |
116 | | uint16_t **setup, uint8_t min_setup, |
117 | | uint8_t *num_setup, |
118 | | uint8_t **param, uint32_t min_param, |
119 | | uint32_t *num_param, |
120 | | uint8_t **data, uint32_t min_data, |
121 | | uint32_t *num_data) |
122 | 0 | { |
123 | 0 | struct cli_trans_state *state = tevent_req_data( |
124 | 0 | req, struct cli_trans_state); |
125 | 0 | NTSTATUS status = NT_STATUS_OK; |
126 | 0 | bool map_dos_errors = true; |
127 | |
|
128 | 0 | if (tevent_req_is_nterror(req, &status)) { |
129 | 0 | goto map_error; |
130 | 0 | } |
131 | | |
132 | 0 | if ((state->num_setup < min_setup) || |
133 | 0 | (state->num_param < min_param) || |
134 | 0 | (state->num_data < min_data)) { |
135 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
136 | 0 | } |
137 | | |
138 | 0 | if (recv_flags2 != NULL) { |
139 | 0 | *recv_flags2 = state->recv_flags2; |
140 | 0 | } |
141 | 0 | if (setup != NULL) { |
142 | 0 | *setup = talloc_move(mem_ctx, &state->setup); |
143 | 0 | *num_setup = state->num_setup; |
144 | 0 | } |
145 | 0 | if (param != NULL) { |
146 | 0 | *param = talloc_move(mem_ctx, &state->param); |
147 | 0 | *num_param = state->num_param; |
148 | 0 | } |
149 | 0 | if (data != NULL) { |
150 | 0 | *data = talloc_move(mem_ctx, &state->data); |
151 | 0 | *num_data = state->num_data; |
152 | 0 | } |
153 | |
|
154 | 0 | map_error: |
155 | 0 | map_dos_errors = state->cli->map_dos_errors; |
156 | |
|
157 | 0 | if (NT_STATUS_IS_DOS(status) && map_dos_errors) { |
158 | 0 | uint8_t eclass = NT_STATUS_DOS_CLASS(status); |
159 | 0 | uint16_t ecode = NT_STATUS_DOS_CODE(status); |
160 | | /* |
161 | | * TODO: is it really a good idea to do a mapping here? |
162 | | * |
163 | | * The old cli_pull_error() also does it, so I do not change |
164 | | * the behavior yet. |
165 | | */ |
166 | 0 | status = dos_to_ntstatus(eclass, ecode); |
167 | 0 | } |
168 | |
|
169 | 0 | return status; |
170 | 0 | } |
171 | | |
172 | | NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli, |
173 | | uint8_t trans_cmd, |
174 | | const char *pipe_name, uint16_t fid, uint16_t function, |
175 | | int flags, |
176 | | uint16_t *setup, uint8_t num_setup, uint8_t max_setup, |
177 | | uint8_t *param, uint32_t num_param, uint32_t max_param, |
178 | | uint8_t *data, uint32_t num_data, uint32_t max_data, |
179 | | uint16_t *recv_flags2, |
180 | | uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup, |
181 | | uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam, |
182 | | uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata) |
183 | 0 | { |
184 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
185 | 0 | struct tevent_context *ev; |
186 | 0 | struct tevent_req *req; |
187 | 0 | NTSTATUS status = NT_STATUS_NO_MEMORY; |
188 | |
|
189 | 0 | if (smbXcli_conn_has_async_calls(cli->conn)) { |
190 | | /* |
191 | | * Can't use sync call while an async call is in flight |
192 | | */ |
193 | 0 | status = NT_STATUS_INVALID_PARAMETER; |
194 | 0 | goto fail; |
195 | 0 | } |
196 | 0 | ev = samba_tevent_context_init(frame); |
197 | 0 | if (ev == NULL) { |
198 | 0 | goto fail; |
199 | 0 | } |
200 | 0 | req = cli_trans_send( |
201 | 0 | frame, /* mem_ctx */ |
202 | 0 | ev, /* ev */ |
203 | 0 | cli, /* cli */ |
204 | 0 | 0, /* additional_flags2 */ |
205 | 0 | trans_cmd, /* cmd */ |
206 | 0 | pipe_name, fid, function, flags, |
207 | 0 | setup, num_setup, max_setup, |
208 | 0 | param, num_param, max_param, |
209 | 0 | data, num_data, max_data); |
210 | 0 | if (req == NULL) { |
211 | 0 | goto fail; |
212 | 0 | } |
213 | 0 | if (!tevent_req_poll_ntstatus(req, ev, &status)) { |
214 | 0 | goto fail; |
215 | 0 | } |
216 | 0 | status = cli_trans_recv( |
217 | 0 | req, mem_ctx, recv_flags2, |
218 | 0 | rsetup, min_rsetup, num_rsetup, |
219 | 0 | rparam, min_rparam, num_rparam, |
220 | 0 | rdata, min_rdata, num_rdata); |
221 | 0 | fail: |
222 | 0 | TALLOC_FREE(frame); |
223 | 0 | return status; |
224 | 0 | } |