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
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
);
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
;
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
;
97 status
= smb2_create_recv(req
, ctx
, &create_parm
);
98 if (!NT_STATUS_IS_OK(status
)) {
99 composite_error(ctx
, status
);
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
;
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
);
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
)) {
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
);
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
);
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
;
204 status
= smb2_create_recv(req
, ctx
, &create_parm
);
205 if (!NT_STATUS_IS_OK(status
)) {
206 composite_error(ctx
, status
);
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
,
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
);
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
;
275 status
= smb2_create_recv(req
, ctx
, &create_parm
);
276 if (!NT_STATUS_IS_OK(status
)) {
277 composite_error(ctx
, status
);
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
);
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
;
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
);
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
;
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
,
392 struct smb2_composite_setpathinfo_state
*state
=
394 struct smb2_composite_setpathinfo_state
);
397 status
= smb2_create_recv(smb2req
, state
, &state
->cr
);
398 if (tevent_req_nterror(req
, status
)) {
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
)) {
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
,
419 struct smb2_composite_setpathinfo_state
*state
=
421 struct smb2_composite_setpathinfo_state
);
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
)) {
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
,
442 struct smb2_composite_setpathinfo_state
*state
=
444 struct smb2_composite_setpathinfo_state
);
447 status
= smb2_close_recv(smb2req
, &state
->cl
);
449 if (tevent_req_nterror(req
, state
->set_status
)) {
453 if (tevent_req_nterror(req
, status
)) {
457 tevent_req_done(req
);
460 NTSTATUS
smb2_composite_setpathinfo_recv(struct tevent_req
*req
)
464 if (tevent_req_is_nterror(req
, &status
)) {
465 tevent_req_received(req
);
469 tevent_req_received(req
);
474 composite setpathinfo call
476 NTSTATUS
smb2_composite_setpathinfo(struct smb2_tree
*tree
, union smb_setfileinfo
*io
)
478 struct tevent_req
*subreq
;
481 TALLOC_CTX
*frame
= talloc_stackframe();
482 struct tevent_context
*ev
= tree
->session
->transport
->ev
;
485 return NT_STATUS_NO_MEMORY
;
488 subreq
= smb2_composite_setpathinfo_send(frame
, ev
, tree
, io
);
489 if (subreq
== NULL
) {
491 return NT_STATUS_NO_MEMORY
;
494 ok
= tevent_req_poll(subreq
, ev
);
496 status
= map_nt_error_from_unix_common(errno
);
501 status
= smb2_composite_setpathinfo_recv(subreq
);
503 if (!NT_STATUS_IS_OK(status
)) {