Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Andrew Tridgell 2005
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 : a composite API for loading a whole file into memory
21 : */
22 :
23 : #include "includes.h"
24 : #include "libcli/raw/libcliraw.h"
25 : #include "libcli/composite/composite.h"
26 : #include "libcli/smb_composite/smb_composite.h"
27 :
28 : /* the stages of this call */
29 : enum loadfile_stage {LOADFILE_OPEN, LOADFILE_READ, LOADFILE_CLOSE};
30 :
31 :
32 : static void loadfile_handler(struct smbcli_request *req);
33 :
34 : struct loadfile_state {
35 : enum loadfile_stage stage;
36 : struct smb_composite_loadfile *io;
37 : struct smbcli_request *req;
38 : union smb_open *io_open;
39 : union smb_read *io_read;
40 : };
41 :
42 : /*
43 : setup for the close
44 : */
45 300 : static NTSTATUS setup_close(struct composite_context *c,
46 : struct smbcli_tree *tree, uint16_t fnum)
47 : {
48 300 : struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
49 0 : union smb_close *io_close;
50 :
51 : /* nothing to read, setup the close */
52 300 : io_close = talloc(c, union smb_close);
53 300 : NT_STATUS_HAVE_NO_MEMORY(io_close);
54 :
55 300 : io_close->close.level = RAW_CLOSE_CLOSE;
56 300 : io_close->close.in.file.fnum = fnum;
57 300 : io_close->close.in.write_time = 0;
58 :
59 300 : state->req = smb_raw_close_send(tree, io_close);
60 300 : NT_STATUS_HAVE_NO_MEMORY(state->req);
61 :
62 : /* call the handler again when the close is done */
63 300 : state->req->async.fn = loadfile_handler;
64 300 : state->req->async.private_data = c;
65 300 : state->stage = LOADFILE_CLOSE;
66 :
67 300 : return NT_STATUS_OK;
68 : }
69 :
70 : /*
71 : called when the open is done - pull the results and setup for the
72 : first readx, or close if the file is zero size
73 : */
74 300 : static NTSTATUS loadfile_open(struct composite_context *c,
75 : struct smb_composite_loadfile *io)
76 : {
77 300 : struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
78 300 : struct smbcli_tree *tree = state->req->tree;
79 0 : NTSTATUS status;
80 :
81 300 : status = smb_raw_open_recv(state->req, c, state->io_open);
82 300 : NT_STATUS_NOT_OK_RETURN(status);
83 :
84 : /* don't allow stupidly large loads */
85 300 : if (state->io_open->ntcreatex.out.size > 100*1000*1000) {
86 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
87 : }
88 :
89 : /* allocate space for the file data */
90 300 : io->out.size = state->io_open->ntcreatex.out.size;
91 300 : io->out.data = talloc_array(c, uint8_t, io->out.size);
92 300 : NT_STATUS_HAVE_NO_MEMORY(io->out.data);
93 :
94 300 : if (io->out.size == 0) {
95 0 : return setup_close(c, tree, state->io_open->ntcreatex.out.file.fnum);
96 : }
97 :
98 : /* setup for the read */
99 300 : state->io_read = talloc(c, union smb_read);
100 300 : NT_STATUS_HAVE_NO_MEMORY(state->io_read);
101 :
102 300 : state->io_read->readx.level = RAW_READ_READX;
103 300 : state->io_read->readx.in.file.fnum = state->io_open->ntcreatex.out.file.fnum;
104 300 : state->io_read->readx.in.offset = 0;
105 300 : state->io_read->readx.in.mincnt = MIN(32768, io->out.size);
106 300 : state->io_read->readx.in.maxcnt = state->io_read->readx.in.mincnt;
107 300 : state->io_read->readx.in.remaining = 0;
108 300 : state->io_read->readx.in.read_for_execute = false;
109 300 : state->io_read->readx.out.data = io->out.data;
110 :
111 300 : state->req = smb_raw_read_send(tree, state->io_read);
112 300 : NT_STATUS_HAVE_NO_MEMORY(state->req);
113 :
114 : /* call the handler again when the first read is done */
115 300 : state->req->async.fn = loadfile_handler;
116 300 : state->req->async.private_data = c;
117 300 : state->stage = LOADFILE_READ;
118 :
119 300 : talloc_free(state->io_open);
120 :
121 300 : return NT_STATUS_OK;
122 : }
123 :
124 :
125 : /*
126 : called when a read is done - pull the results and setup for the
127 : next read, or close if the file is all done
128 : */
129 600 : static NTSTATUS loadfile_read(struct composite_context *c,
130 : struct smb_composite_loadfile *io)
131 : {
132 600 : struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
133 600 : struct smbcli_tree *tree = state->req->tree;
134 0 : NTSTATUS status;
135 :
136 600 : status = smb_raw_read_recv(state->req, state->io_read);
137 600 : NT_STATUS_NOT_OK_RETURN(status);
138 :
139 : /* we might be done */
140 600 : if (state->io_read->readx.in.offset +
141 600 : state->io_read->readx.out.nread == io->out.size) {
142 300 : return setup_close(c, tree, state->io_read->readx.in.file.fnum);
143 : }
144 :
145 : /* setup for the next read */
146 300 : state->io_read->readx.in.offset += state->io_read->readx.out.nread;
147 300 : state->io_read->readx.in.mincnt = MIN(32768, io->out.size - state->io_read->readx.in.offset);
148 300 : state->io_read->readx.out.data = io->out.data + state->io_read->readx.in.offset;
149 :
150 300 : state->req = smb_raw_read_send(tree, state->io_read);
151 300 : NT_STATUS_HAVE_NO_MEMORY(state->req);
152 :
153 : /* call the handler again when the read is done */
154 300 : state->req->async.fn = loadfile_handler;
155 300 : state->req->async.private_data = c;
156 :
157 300 : return NT_STATUS_OK;
158 : }
159 :
160 : /*
161 : called when the close is done, check the status and cleanup
162 : */
163 300 : static NTSTATUS loadfile_close(struct composite_context *c,
164 : struct smb_composite_loadfile *io)
165 : {
166 300 : struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
167 0 : NTSTATUS status;
168 :
169 300 : status = smbcli_request_simple_recv(state->req);
170 300 : NT_STATUS_NOT_OK_RETURN(status);
171 :
172 300 : c->state = COMPOSITE_STATE_DONE;
173 :
174 300 : return NT_STATUS_OK;
175 : }
176 :
177 :
178 : /*
179 : handler for completion of a sub-request in loadfile
180 : */
181 1200 : static void loadfile_handler(struct smbcli_request *req)
182 : {
183 1200 : struct composite_context *c = (struct composite_context *)req->async.private_data;
184 1200 : struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
185 :
186 : /* when this handler is called, the stage indicates what
187 : call has just finished */
188 1200 : switch (state->stage) {
189 300 : case LOADFILE_OPEN:
190 300 : c->status = loadfile_open(c, state->io);
191 300 : break;
192 :
193 600 : case LOADFILE_READ:
194 600 : c->status = loadfile_read(c, state->io);
195 600 : break;
196 :
197 300 : case LOADFILE_CLOSE:
198 300 : c->status = loadfile_close(c, state->io);
199 300 : break;
200 : }
201 :
202 1200 : if (!NT_STATUS_IS_OK(c->status)) {
203 0 : c->state = COMPOSITE_STATE_ERROR;
204 : }
205 :
206 1200 : if (c->state >= COMPOSITE_STATE_DONE &&
207 300 : c->async.fn) {
208 300 : c->async.fn(c);
209 : }
210 1200 : }
211 :
212 : /*
213 : composite loadfile call - does an openx followed by a number of readx calls,
214 : followed by a close
215 : */
216 300 : struct composite_context *smb_composite_loadfile_send(struct smbcli_tree *tree,
217 : struct smb_composite_loadfile *io)
218 : {
219 0 : struct composite_context *c;
220 0 : struct loadfile_state *state;
221 :
222 300 : c = talloc_zero(tree, struct composite_context);
223 300 : if (c == NULL) goto failed;
224 :
225 300 : state = talloc(c, struct loadfile_state);
226 300 : if (state == NULL) goto failed;
227 :
228 300 : state->io = io;
229 :
230 300 : c->private_data = state;
231 300 : c->state = COMPOSITE_STATE_IN_PROGRESS;
232 300 : c->event_ctx = tree->session->transport->ev;
233 :
234 : /* setup for the open */
235 300 : state->io_open = talloc_zero(c, union smb_open);
236 300 : if (state->io_open == NULL) goto failed;
237 :
238 300 : state->io_open->ntcreatex.level = RAW_OPEN_NTCREATEX;
239 300 : state->io_open->ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
240 300 : state->io_open->ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
241 300 : state->io_open->ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
242 300 : state->io_open->ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
243 300 : state->io_open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
244 300 : state->io_open->ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
245 300 : state->io_open->ntcreatex.in.fname = io->in.fname;
246 :
247 : /* send the open on its way */
248 300 : state->req = smb_raw_open_send(tree, state->io_open);
249 300 : if (state->req == NULL) goto failed;
250 :
251 : /* setup the callback handler */
252 300 : state->req->async.fn = loadfile_handler;
253 300 : state->req->async.private_data = c;
254 300 : state->stage = LOADFILE_OPEN;
255 :
256 300 : return c;
257 :
258 0 : failed:
259 0 : talloc_free(c);
260 0 : return NULL;
261 : }
262 :
263 :
264 : /*
265 : composite loadfile call - recv side
266 : */
267 300 : NTSTATUS smb_composite_loadfile_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
268 : {
269 0 : NTSTATUS status;
270 :
271 300 : status = composite_wait(c);
272 :
273 300 : if (NT_STATUS_IS_OK(status)) {
274 300 : struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state);
275 300 : talloc_steal(mem_ctx, state->io->out.data);
276 : }
277 :
278 300 : talloc_free(c);
279 300 : return status;
280 : }
281 :
282 :
283 : /*
284 : composite loadfile call - sync interface
285 : */
286 0 : NTSTATUS smb_composite_loadfile(struct smbcli_tree *tree,
287 : TALLOC_CTX *mem_ctx,
288 : struct smb_composite_loadfile *io)
289 : {
290 0 : struct composite_context *c = smb_composite_loadfile_send(tree, io);
291 0 : return smb_composite_loadfile_recv(c, mem_ctx);
292 : }
293 :
|