Line data Source code
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 *subreq;
29 : uint16_t recv_flags2;
30 : uint16_t *setup;
31 : uint8_t num_setup;
32 : uint8_t *param;
33 : uint32_t num_param;
34 : uint8_t *data;
35 : uint32_t num_data;
36 : };
37 :
38 : static void cli_trans_done(struct tevent_req *subreq);
39 : static bool cli_trans_cancel(struct tevent_req *req);
40 :
41 20484 : struct tevent_req *cli_trans_send(
42 : TALLOC_CTX *mem_ctx, struct tevent_context *ev,
43 : struct cli_state *cli, uint16_t additional_flags2, uint8_t cmd,
44 : const char *pipe_name, uint16_t fid, uint16_t function, int flags,
45 : uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
46 : uint8_t *param, uint32_t num_param, uint32_t max_param,
47 : uint8_t *data, uint32_t num_data, uint32_t max_data)
48 : {
49 0 : struct tevent_req *req;
50 0 : struct cli_trans_state *state;
51 20484 : uint8_t additional_flags = 0;
52 20484 : uint8_t clear_flags = 0;
53 20484 : uint16_t clear_flags2 = 0;
54 :
55 20484 : req = tevent_req_create(mem_ctx, &state, struct cli_trans_state);
56 20484 : if (req == NULL) {
57 0 : return NULL;
58 : }
59 20484 : state->cli = cli;
60 :
61 40968 : state->subreq = smb1cli_trans_send(state, ev,
62 : cli->conn, cmd,
63 : additional_flags, clear_flags,
64 : additional_flags2, clear_flags2,
65 20484 : cli->timeout,
66 : cli->smb1.pid,
67 : cli->smb1.tcon,
68 : cli->smb1.session,
69 : pipe_name, fid, function, flags,
70 : setup, num_setup, max_setup,
71 : param, num_param, max_param,
72 : data, num_data, max_data);
73 20484 : if (tevent_req_nomem(state->subreq, req)) {
74 0 : return tevent_req_post(req, ev);
75 : }
76 20484 : tevent_req_set_callback(state->subreq, cli_trans_done, req);
77 20484 : tevent_req_set_cancel_fn(req, cli_trans_cancel);
78 20484 : return req;
79 : }
80 :
81 0 : static bool cli_trans_cancel(struct tevent_req *req)
82 : {
83 0 : struct cli_trans_state *state = tevent_req_data(
84 : req, struct cli_trans_state);
85 0 : bool ok;
86 :
87 0 : ok = tevent_req_cancel(state->subreq);
88 0 : return ok;
89 : }
90 :
91 20484 : static void cli_trans_done(struct tevent_req *subreq)
92 : {
93 20484 : struct tevent_req *req = tevent_req_callback_data(
94 : subreq, struct tevent_req);
95 20484 : struct cli_trans_state *state = tevent_req_data(
96 : req, struct cli_trans_state);
97 0 : NTSTATUS status;
98 :
99 20484 : status = smb1cli_trans_recv(
100 : subreq,
101 : state,
102 : &state->recv_flags2,
103 : &state->setup, 0, &state->num_setup,
104 : &state->param, 0, &state->num_param,
105 : &state->data, 0, &state->num_data);
106 20484 : TALLOC_FREE(subreq);
107 20484 : if (tevent_req_nterror(req, status)) {
108 6090 : return;
109 : }
110 14394 : tevent_req_done(req);
111 : }
112 :
113 20484 : NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
114 : uint16_t *recv_flags2,
115 : uint16_t **setup, uint8_t min_setup,
116 : uint8_t *num_setup,
117 : uint8_t **param, uint32_t min_param,
118 : uint32_t *num_param,
119 : uint8_t **data, uint32_t min_data,
120 : uint32_t *num_data)
121 : {
122 20484 : struct cli_trans_state *state = tevent_req_data(
123 : req, struct cli_trans_state);
124 20484 : NTSTATUS status = NT_STATUS_OK;
125 20484 : bool map_dos_errors = true;
126 :
127 20484 : if (tevent_req_is_nterror(req, &status)) {
128 6090 : goto map_error;
129 : }
130 :
131 14394 : if ((state->num_setup < min_setup) ||
132 14394 : (state->num_param < min_param) ||
133 14394 : (state->num_data < min_data)) {
134 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
135 : }
136 :
137 14394 : if (recv_flags2 != NULL) {
138 3603 : *recv_flags2 = state->recv_flags2;
139 : }
140 14394 : if (setup != NULL) {
141 0 : *setup = talloc_move(mem_ctx, &state->setup);
142 0 : *num_setup = state->num_setup;
143 : }
144 14394 : if (param != NULL) {
145 1948 : *param = talloc_move(mem_ctx, &state->param);
146 1948 : *num_param = state->num_param;
147 : }
148 14394 : if (data != NULL) {
149 13262 : *data = talloc_move(mem_ctx, &state->data);
150 13262 : *num_data = state->num_data;
151 : }
152 :
153 1132 : map_error:
154 20484 : map_dos_errors = state->cli->map_dos_errors;
155 20484 : state->cli->raw_status = status;
156 :
157 20484 : if (NT_STATUS_IS_DOS(status) && map_dos_errors) {
158 8 : uint8_t eclass = NT_STATUS_DOS_CLASS(status);
159 8 : 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 8 : status = dos_to_ntstatus(eclass, ecode);
167 : }
168 :
169 20484 : return status;
170 : }
171 :
172 4761 : 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 : {
184 4761 : TALLOC_CTX *frame = talloc_stackframe();
185 0 : struct tevent_context *ev;
186 0 : struct tevent_req *req;
187 4761 : NTSTATUS status = NT_STATUS_NO_MEMORY;
188 :
189 4761 : 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 : }
196 4761 : ev = samba_tevent_context_init(frame);
197 4761 : if (ev == NULL) {
198 0 : goto fail;
199 : }
200 4761 : req = cli_trans_send(
201 : frame, /* mem_ctx */
202 : ev, /* ev */
203 : cli, /* cli */
204 : 0, /* additional_flags2 */
205 : trans_cmd, /* cmd */
206 : pipe_name, fid, function, flags,
207 : setup, num_setup, max_setup,
208 : param, num_param, max_param,
209 : data, num_data, max_data);
210 4761 : if (req == NULL) {
211 0 : goto fail;
212 : }
213 4761 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
214 0 : goto fail;
215 : }
216 4761 : status = cli_trans_recv(
217 : req, mem_ctx, recv_flags2,
218 : rsetup, min_rsetup, num_rsetup,
219 : rparam, min_rparam, num_rparam,
220 : rdata, min_rdata, num_rdata);
221 4761 : fail:
222 4761 : TALLOC_FREE(frame);
223 4761 : return status;
224 : }
|