smbd: Fix cached dos attributes
[Samba.git] / source3 / libsmb / clitrans.c
blobe5b4c4a4618766e9c0f12d195c5b26d59f9e2831
1 /*
2 Unix SMB/CIFS implementation.
3 client transaction calls
4 Copyright (C) Andrew Tridgell 1994-1998
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.
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.
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/>.
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"
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;
38 static void cli_trans_done(struct tevent_req *subreq);
39 static bool cli_trans_cancel(struct tevent_req *req);
41 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)
49 struct tevent_req *req;
50 struct cli_trans_state *state;
51 uint8_t additional_flags = 0;
52 uint8_t clear_flags = 0;
53 uint16_t clear_flags2 = 0;
55 req = tevent_req_create(mem_ctx, &state, struct cli_trans_state);
56 if (req == NULL) {
57 return NULL;
59 state->cli = cli;
61 state->subreq = smb1cli_trans_send(state, ev,
62 cli->conn, cmd,
63 additional_flags, clear_flags,
64 additional_flags2, clear_flags2,
65 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 if (tevent_req_nomem(state->subreq, req)) {
74 return tevent_req_post(req, ev);
76 tevent_req_set_callback(state->subreq, cli_trans_done, req);
77 tevent_req_set_cancel_fn(req, cli_trans_cancel);
78 return req;
81 static bool cli_trans_cancel(struct tevent_req *req)
83 struct cli_trans_state *state = tevent_req_data(
84 req, struct cli_trans_state);
85 bool ok;
87 ok = tevent_req_cancel(state->subreq);
88 return ok;
91 static void cli_trans_done(struct tevent_req *subreq)
93 struct tevent_req *req = tevent_req_callback_data(
94 subreq, struct tevent_req);
95 struct cli_trans_state *state = tevent_req_data(
96 req, struct cli_trans_state);
97 NTSTATUS status;
99 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 TALLOC_FREE(subreq);
107 if (tevent_req_nterror(req, status)) {
108 return;
110 tevent_req_done(req);
113 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)
122 struct cli_trans_state *state = tevent_req_data(
123 req, struct cli_trans_state);
124 NTSTATUS status = NT_STATUS_OK;
125 bool map_dos_errors = true;
127 if (tevent_req_is_nterror(req, &status)) {
128 goto map_error;
131 if ((state->num_setup < min_setup) ||
132 (state->num_param < min_param) ||
133 (state->num_data < min_data)) {
134 return NT_STATUS_INVALID_NETWORK_RESPONSE;
137 if (recv_flags2 != NULL) {
138 *recv_flags2 = state->recv_flags2;
140 if (setup != NULL) {
141 *setup = talloc_move(mem_ctx, &state->setup);
142 *num_setup = state->num_setup;
144 if (param != NULL) {
145 *param = talloc_move(mem_ctx, &state->param);
146 *num_param = state->num_param;
148 if (data != NULL) {
149 *data = talloc_move(mem_ctx, &state->data);
150 *num_data = state->num_data;
153 map_error:
154 map_dos_errors = state->cli->map_dos_errors;
155 state->cli->raw_status = status;
157 if (NT_STATUS_IS_DOS(status) && map_dos_errors) {
158 uint8_t eclass = NT_STATUS_DOS_CLASS(status);
159 uint16_t ecode = NT_STATUS_DOS_CODE(status);
161 * TODO: is it really a good idea to do a mapping here?
163 * The old cli_pull_error() also does it, so I do not change
164 * the behavior yet.
166 status = dos_to_ntstatus(eclass, ecode);
169 return status;
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)
184 TALLOC_CTX *frame = talloc_stackframe();
185 struct tevent_context *ev;
186 struct tevent_req *req;
187 NTSTATUS status = NT_STATUS_NO_MEMORY;
189 if (smbXcli_conn_has_async_calls(cli->conn)) {
191 * Can't use sync call while an async call is in flight
193 status = NT_STATUS_INVALID_PARAMETER;
194 goto fail;
196 ev = samba_tevent_context_init(frame);
197 if (ev == NULL) {
198 goto fail;
200 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 if (req == NULL) {
211 goto fail;
213 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
214 goto fail;
216 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 fail:
222 TALLOC_FREE(frame);
223 return status;