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 
cli_trans_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,uint16_t additional_flags2,uint8_t cmd,const char * pipe_name,uint16_t fid,uint16_t function,int flags,uint16_t * setup,uint8_t num_setup,uint8_t max_setup,uint8_t * param,uint32_t num_param,uint32_t max_param,uint8_t * data,uint32_t num_data,uint32_t max_data)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)
48 {
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;
54 
55 	req = tevent_req_create(mem_ctx, &state, struct cli_trans_state);
56 	if (req == NULL) {
57 		return NULL;
58 	}
59 	state->cli = cli;
60 
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);
75 	}
76 	tevent_req_set_callback(state->subreq, cli_trans_done, req);
77 	tevent_req_set_cancel_fn(req, cli_trans_cancel);
78 	return req;
79 }
80 
cli_trans_cancel(struct tevent_req * req)81 static bool cli_trans_cancel(struct tevent_req *req)
82 {
83 	struct cli_trans_state *state = tevent_req_data(
84 		req, struct cli_trans_state);
85 	bool ok;
86 
87 	ok = tevent_req_cancel(state->subreq);
88 	return ok;
89 }
90 
cli_trans_done(struct tevent_req * subreq)91 static void cli_trans_done(struct tevent_req *subreq)
92 {
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;
98 
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;
109 	}
110 	tevent_req_done(req);
111 }
112 
cli_trans_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,uint16_t * recv_flags2,uint16_t ** setup,uint8_t min_setup,uint8_t * num_setup,uint8_t ** param,uint32_t min_param,uint32_t * num_param,uint8_t ** data,uint32_t min_data,uint32_t * num_data)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)
121 {
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;
126 
127 	if (tevent_req_is_nterror(req, &status)) {
128 		goto map_error;
129 	}
130 
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;
135 	}
136 
137 	if (recv_flags2 != NULL) {
138 		*recv_flags2 = state->recv_flags2;
139 	}
140 	if (setup != NULL) {
141 		*setup = talloc_move(mem_ctx, &state->setup);
142 		*num_setup = state->num_setup;
143 	}
144 	if (param != NULL) {
145 		*param = talloc_move(mem_ctx, &state->param);
146 		*num_param = state->num_param;
147 	}
148 	if (data != NULL) {
149 		*data = talloc_move(mem_ctx, &state->data);
150 		*num_data = state->num_data;
151 	}
152 
153 map_error:
154 	map_dos_errors = state->cli->map_dos_errors;
155 	state->cli->raw_status = status;
156 
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);
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 		status = dos_to_ntstatus(eclass, ecode);
167 	}
168 
169 	return status;
170 }
171 
cli_trans(TALLOC_CTX * mem_ctx,struct cli_state * cli,uint8_t trans_cmd,const char * pipe_name,uint16_t fid,uint16_t function,int flags,uint16_t * setup,uint8_t num_setup,uint8_t max_setup,uint8_t * param,uint32_t num_param,uint32_t max_param,uint8_t * data,uint32_t num_data,uint32_t max_data,uint16_t * recv_flags2,uint16_t ** rsetup,uint8_t min_rsetup,uint8_t * num_rsetup,uint8_t ** rparam,uint32_t min_rparam,uint32_t * num_rparam,uint8_t ** rdata,uint32_t min_rdata,uint32_t * num_rdata)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 {
184 	TALLOC_CTX *frame = talloc_stackframe();
185 	struct tevent_context *ev;
186 	struct tevent_req *req;
187 	NTSTATUS status = NT_STATUS_NO_MEMORY;
188 
189 	if (smbXcli_conn_has_async_calls(cli->conn)) {
190 		/*
191 		 * Can't use sync call while an async call is in flight
192 		 */
193 		status = NT_STATUS_INVALID_PARAMETER;
194 		goto fail;
195 	}
196 	ev = samba_tevent_context_init(frame);
197 	if (ev == NULL) {
198 		goto fail;
199 	}
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;
212 	}
213 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
214 		goto fail;
215 	}
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;
224 }
225