ctdb-scripts: Move connection tracking to 10.interface
[samba4-gss.git] / source4 / libcli / smb_composite / smb2.c
blobd2a4a851a765393ccacb917722de04a47ee79dbf
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2008
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 a composite API for making SMB-like calls using SMB2. This is useful
21 as SMB2 often requires more than one requests where a single SMB
22 request would do. In converting code that uses SMB to use SMB2,
23 these routines make life a lot easier
27 #include "includes.h"
28 #include <tevent.h>
29 #include "lib/util/tevent_ntstatus.h"
30 #include "libcli/raw/libcliraw.h"
31 #include "libcli/raw/raw_proto.h"
32 #include "libcli/composite/composite.h"
33 #include "libcli/smb_composite/smb_composite.h"
34 #include "libcli/smb2/smb2_calls.h"
37 continue after a SMB2 close
39 static void continue_close(struct smb2_request *req)
41 struct composite_context *ctx = talloc_get_type(req->async.private_data,
42 struct composite_context);
43 NTSTATUS status;
44 struct smb2_close close_parm;
46 status = smb2_close_recv(req, &close_parm);
47 composite_error(ctx, status);
50 struct smb2_composite_unlink_state {
51 bool truncate_if_needed;
52 struct smb2_handle handle;
56 continue after the truncate in a composite unlink
58 static void continue_truncate(struct smb2_request *req)
60 struct composite_context *ctx = talloc_get_type(req->async.private_data,
61 struct composite_context);
62 struct smb2_composite_unlink_state *state =
63 talloc_get_type_abort(ctx->private_data,
64 struct smb2_composite_unlink_state);
65 struct smb2_tree *tree = req->tree;
66 struct smb2_close close_parm;
67 NTSTATUS status;
69 status = smb2_setinfo_recv(req);
70 if (!NT_STATUS_IS_OK(status)) {
71 /* we ignore errors as we should not leak the handle */
74 ZERO_STRUCT(close_parm);
75 close_parm.in.file.handle = state->handle;
76 close_parm.in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
78 req = smb2_close_send(tree, &close_parm);
79 composite_continue_smb2(ctx, req, continue_close, ctx);
83 continue after the create in a composite unlink
85 static void continue_unlink(struct smb2_request *req)
87 struct composite_context *ctx = talloc_get_type(req->async.private_data,
88 struct composite_context);
89 struct smb2_composite_unlink_state *state =
90 talloc_get_type_abort(ctx->private_data,
91 struct smb2_composite_unlink_state);
92 struct smb2_tree *tree = req->tree;
93 struct smb2_create create_parm;
94 struct smb2_close close_parm;
95 NTSTATUS status;
97 status = smb2_create_recv(req, ctx, &create_parm);
98 if (!NT_STATUS_IS_OK(status)) {
99 composite_error(ctx, status);
100 return;
103 if (create_parm.out.size != 0 &&
104 state->truncate_if_needed)
106 union smb_setfileinfo sinfo;
108 state->handle = create_parm.out.file.handle;
110 ZERO_STRUCT(sinfo);
111 sinfo.end_of_file_info.level =
112 RAW_SFILEINFO_END_OF_FILE_INFORMATION;
113 sinfo.end_of_file_info.in.file.handle = state->handle;
114 sinfo.end_of_file_info.in.size = 0;
115 req = smb2_setinfo_file_send(tree, &sinfo);
116 composite_continue_smb2(ctx, req, continue_truncate, ctx);
117 return;
120 ZERO_STRUCT(close_parm);
121 close_parm.in.file.handle = create_parm.out.file.handle;
123 req = smb2_close_send(tree, &close_parm);
124 composite_continue_smb2(ctx, req, continue_close, ctx);
128 composite SMB2 unlink call
130 struct composite_context *smb2_composite_unlink_send(struct smb2_tree *tree,
131 union smb_unlink *io)
133 struct composite_context *ctx;
134 struct smb2_composite_unlink_state *state = NULL;
135 struct smb2_create create_parm;
136 struct smb2_request *req;
138 ctx = composite_create(tree, tree->session->transport->ev);
139 if (ctx == NULL) return NULL;
141 state = talloc_zero(ctx, struct smb2_composite_unlink_state);
142 if (composite_nomem(state, ctx)) {
143 return ctx;
145 ctx->private_data = state;
146 state->truncate_if_needed = io->unlink.in.truncate_if_needed;
148 /* check for wildcards - we could support these with a
149 search, but for now they aren't necessary */
150 if (strpbrk(io->unlink.in.pattern, "*?<>") != NULL) {
151 composite_error(ctx, NT_STATUS_NOT_SUPPORTED);
152 return ctx;
155 ZERO_STRUCT(create_parm);
156 create_parm.in.desired_access = SEC_STD_DELETE;
157 if (state->truncate_if_needed) {
158 create_parm.in.desired_access |= SEC_FILE_WRITE_DATA;
160 create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
161 create_parm.in.share_access =
162 NTCREATEX_SHARE_ACCESS_DELETE|
163 NTCREATEX_SHARE_ACCESS_READ|
164 NTCREATEX_SHARE_ACCESS_WRITE;
165 create_parm.in.create_options =
166 NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
167 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
168 create_parm.in.fname = io->unlink.in.pattern;
169 if (create_parm.in.fname[0] == '\\') {
170 create_parm.in.fname++;
173 req = smb2_create_send(tree, &create_parm);
175 composite_continue_smb2(ctx, req, continue_unlink, ctx);
176 return ctx;
181 composite unlink call - sync interface
183 NTSTATUS smb2_composite_unlink(struct smb2_tree *tree, union smb_unlink *io)
185 struct composite_context *c = smb2_composite_unlink_send(tree, io);
186 return composite_wait_free(c);
193 continue after the create in a composite mkdir
195 static void continue_mkdir(struct smb2_request *req)
197 struct composite_context *ctx = talloc_get_type(req->async.private_data,
198 struct composite_context);
199 struct smb2_tree *tree = req->tree;
200 struct smb2_create create_parm;
201 struct smb2_close close_parm;
202 NTSTATUS status;
204 status = smb2_create_recv(req, ctx, &create_parm);
205 if (!NT_STATUS_IS_OK(status)) {
206 composite_error(ctx, status);
207 return;
210 ZERO_STRUCT(close_parm);
211 close_parm.in.file.handle = create_parm.out.file.handle;
213 req = smb2_close_send(tree, &close_parm);
214 composite_continue_smb2(ctx, req, continue_close, ctx);
218 composite SMB2 mkdir call
220 struct composite_context *smb2_composite_mkdir_send(struct smb2_tree *tree,
221 union smb_mkdir *io)
223 struct composite_context *ctx;
224 struct smb2_create create_parm;
225 struct smb2_request *req;
227 ctx = composite_create(tree, tree->session->transport->ev);
228 if (ctx == NULL) return NULL;
230 ZERO_STRUCT(create_parm);
232 create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
233 create_parm.in.share_access =
234 NTCREATEX_SHARE_ACCESS_READ|
235 NTCREATEX_SHARE_ACCESS_WRITE;
236 create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
237 create_parm.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY;
238 create_parm.in.create_disposition = NTCREATEX_DISP_CREATE;
239 create_parm.in.fname = io->mkdir.in.path;
240 if (create_parm.in.fname[0] == '\\') {
241 create_parm.in.fname++;
244 req = smb2_create_send(tree, &create_parm);
246 composite_continue_smb2(ctx, req, continue_mkdir, ctx);
248 return ctx;
253 composite mkdir call - sync interface
255 NTSTATUS smb2_composite_mkdir(struct smb2_tree *tree, union smb_mkdir *io)
257 struct composite_context *c = smb2_composite_mkdir_send(tree, io);
258 return composite_wait_free(c);
264 continue after the create in a composite rmdir
266 static void continue_rmdir(struct smb2_request *req)
268 struct composite_context *ctx = talloc_get_type(req->async.private_data,
269 struct composite_context);
270 struct smb2_tree *tree = req->tree;
271 struct smb2_create create_parm;
272 struct smb2_close close_parm;
273 NTSTATUS status;
275 status = smb2_create_recv(req, ctx, &create_parm);
276 if (!NT_STATUS_IS_OK(status)) {
277 composite_error(ctx, status);
278 return;
281 ZERO_STRUCT(close_parm);
282 close_parm.in.file.handle = create_parm.out.file.handle;
284 req = smb2_close_send(tree, &close_parm);
285 composite_continue_smb2(ctx, req, continue_close, ctx);
289 composite SMB2 rmdir call
291 struct composite_context *smb2_composite_rmdir_send(struct smb2_tree *tree,
292 struct smb_rmdir *io)
294 struct composite_context *ctx;
295 struct smb2_create create_parm;
296 struct smb2_request *req;
298 ctx = composite_create(tree, tree->session->transport->ev);
299 if (ctx == NULL) return NULL;
301 ZERO_STRUCT(create_parm);
302 create_parm.in.desired_access = SEC_STD_DELETE;
303 create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
304 create_parm.in.share_access =
305 NTCREATEX_SHARE_ACCESS_DELETE|
306 NTCREATEX_SHARE_ACCESS_READ|
307 NTCREATEX_SHARE_ACCESS_WRITE;
308 create_parm.in.create_options =
309 NTCREATEX_OPTIONS_DIRECTORY |
310 NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
311 create_parm.in.fname = io->in.path;
312 if (create_parm.in.fname[0] == '\\') {
313 create_parm.in.fname++;
316 req = smb2_create_send(tree, &create_parm);
318 composite_continue_smb2(ctx, req, continue_rmdir, ctx);
319 return ctx;
324 composite rmdir call - sync interface
326 NTSTATUS smb2_composite_rmdir(struct smb2_tree *tree, struct smb_rmdir *io)
328 struct composite_context *c = smb2_composite_rmdir_send(tree, io);
329 return composite_wait_free(c);
332 struct smb2_composite_setpathinfo_state {
333 struct smb2_tree *tree;
334 union smb_setfileinfo io;
335 NTSTATUS set_status;
336 struct smb2_create cr;
337 struct smb2_close cl;
340 static void smb2_composite_setpathinfo_create_done(struct smb2_request *smb2req);
343 composite SMB2 setpathinfo call
345 struct tevent_req *smb2_composite_setpathinfo_send(TALLOC_CTX *mem_ctx,
346 struct tevent_context *ev,
347 struct smb2_tree *tree,
348 const union smb_setfileinfo *io)
350 struct tevent_req *req;
351 struct smb2_composite_setpathinfo_state *state;
352 struct smb2_request *smb2req;
354 req = tevent_req_create(mem_ctx, &state,
355 struct smb2_composite_setpathinfo_state);
356 if (req == NULL) {
357 return NULL;
360 state->tree = tree;
361 state->io = *io;
363 state->cr.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
364 state->cr.in.create_disposition = NTCREATEX_DISP_OPEN;
365 state->cr.in.share_access =
366 NTCREATEX_SHARE_ACCESS_DELETE|
367 NTCREATEX_SHARE_ACCESS_READ|
368 NTCREATEX_SHARE_ACCESS_WRITE;
369 state->cr.in.create_options = 0;
370 state->cr.in.fname = state->io.generic.in.file.path;
371 if (state->cr.in.fname[0] == '\\') {
372 state->cr.in.fname++;
375 smb2req = smb2_create_send(tree, &state->cr);
376 if (tevent_req_nomem(smb2req, req)) {
377 return tevent_req_post(req, ev);
379 smb2req->async.fn = smb2_composite_setpathinfo_create_done;
380 smb2req->async.private_data = req;
382 return req;
385 static void smb2_composite_setpathinfo_setinfo_done(struct smb2_request *smb2req);
387 static void smb2_composite_setpathinfo_create_done(struct smb2_request *smb2req)
389 struct tevent_req *req =
390 talloc_get_type_abort(smb2req->async.private_data,
391 struct tevent_req);
392 struct smb2_composite_setpathinfo_state *state =
393 tevent_req_data(req,
394 struct smb2_composite_setpathinfo_state);
395 NTSTATUS status;
397 status = smb2_create_recv(smb2req, state, &state->cr);
398 if (tevent_req_nterror(req, status)) {
399 return;
402 state->io.generic.in.file.handle = state->cr.out.file.handle;
404 smb2req = smb2_setinfo_file_send(state->tree, &state->io);
405 if (tevent_req_nomem(smb2req, req)) {
406 return;
408 smb2req->async.fn = smb2_composite_setpathinfo_setinfo_done;
409 smb2req->async.private_data = req;
412 static void smb2_composite_setpathinfo_close_done(struct smb2_request *smb2req);
414 static void smb2_composite_setpathinfo_setinfo_done(struct smb2_request *smb2req)
416 struct tevent_req *req =
417 talloc_get_type_abort(smb2req->async.private_data,
418 struct tevent_req);
419 struct smb2_composite_setpathinfo_state *state =
420 tevent_req_data(req,
421 struct smb2_composite_setpathinfo_state);
422 NTSTATUS status;
424 status = smb2_setinfo_recv(smb2req);
425 state->set_status = status;
427 state->cl.in.file.handle = state->io.generic.in.file.handle;
429 smb2req = smb2_close_send(state->tree, &state->cl);
430 if (tevent_req_nomem(smb2req, req)) {
431 return;
433 smb2req->async.fn = smb2_composite_setpathinfo_close_done;
434 smb2req->async.private_data = req;
437 static void smb2_composite_setpathinfo_close_done(struct smb2_request *smb2req)
439 struct tevent_req *req =
440 talloc_get_type_abort(smb2req->async.private_data,
441 struct tevent_req);
442 struct smb2_composite_setpathinfo_state *state =
443 tevent_req_data(req,
444 struct smb2_composite_setpathinfo_state);
445 NTSTATUS status;
447 status = smb2_close_recv(smb2req, &state->cl);
449 if (tevent_req_nterror(req, state->set_status)) {
450 return;
453 if (tevent_req_nterror(req, status)) {
454 return;
457 tevent_req_done(req);
460 NTSTATUS smb2_composite_setpathinfo_recv(struct tevent_req *req)
462 NTSTATUS status;
464 if (tevent_req_is_nterror(req, &status)) {
465 tevent_req_received(req);
466 return status;
469 tevent_req_received(req);
470 return NT_STATUS_OK;
474 composite setpathinfo call
476 NTSTATUS smb2_composite_setpathinfo(struct smb2_tree *tree, union smb_setfileinfo *io)
478 struct tevent_req *subreq;
479 NTSTATUS status;
480 bool ok;
481 TALLOC_CTX *frame = talloc_stackframe();
482 struct tevent_context *ev = tree->session->transport->ev;
484 if (frame == NULL) {
485 return NT_STATUS_NO_MEMORY;
488 subreq = smb2_composite_setpathinfo_send(frame, ev, tree, io);
489 if (subreq == NULL) {
490 TALLOC_FREE(frame);
491 return NT_STATUS_NO_MEMORY;
494 ok = tevent_req_poll(subreq, ev);
495 if (!ok) {
496 status = map_nt_error_from_unix_common(errno);
497 TALLOC_FREE(frame);
498 return status;
501 status = smb2_composite_setpathinfo_recv(subreq);
502 TALLOC_FREE(subreq);
503 if (!NT_STATUS_IS_OK(status)) {
504 TALLOC_FREE(frame);
505 return status;
508 TALLOC_FREE(frame);
509 return NT_STATUS_OK;