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
);
51 continue after the create in a composite unlink
53 static void continue_unlink(struct smb2_request
*req
)
55 struct composite_context
*ctx
= talloc_get_type(req
->async
.private_data
,
56 struct composite_context
);
57 struct smb2_tree
*tree
= req
->tree
;
58 struct smb2_create create_parm
;
59 struct smb2_close close_parm
;
62 status
= smb2_create_recv(req
, ctx
, &create_parm
);
63 if (!NT_STATUS_IS_OK(status
)) {
64 composite_error(ctx
, status
);
68 ZERO_STRUCT(close_parm
);
69 close_parm
.in
.file
.handle
= create_parm
.out
.file
.handle
;
71 req
= smb2_close_send(tree
, &close_parm
);
72 composite_continue_smb2(ctx
, req
, continue_close
, ctx
);
76 composite SMB2 unlink call
78 struct composite_context
*smb2_composite_unlink_send(struct smb2_tree
*tree
,
81 struct composite_context
*ctx
;
82 struct smb2_create create_parm
;
83 struct smb2_request
*req
;
85 ctx
= composite_create(tree
, tree
->session
->transport
->ev
);
86 if (ctx
== NULL
) return NULL
;
88 /* check for wildcards - we could support these with a
89 search, but for now they aren't necessary */
90 if (strpbrk(io
->unlink
.in
.pattern
, "*?<>") != NULL
) {
91 composite_error(ctx
, NT_STATUS_NOT_SUPPORTED
);
95 ZERO_STRUCT(create_parm
);
96 create_parm
.in
.desired_access
= SEC_STD_DELETE
;
97 create_parm
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
98 create_parm
.in
.share_access
=
99 NTCREATEX_SHARE_ACCESS_DELETE
|
100 NTCREATEX_SHARE_ACCESS_READ
|
101 NTCREATEX_SHARE_ACCESS_WRITE
;
102 create_parm
.in
.create_options
=
103 NTCREATEX_OPTIONS_DELETE_ON_CLOSE
|
104 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
105 create_parm
.in
.fname
= io
->unlink
.in
.pattern
;
106 if (create_parm
.in
.fname
[0] == '\\') {
107 create_parm
.in
.fname
++;
110 req
= smb2_create_send(tree
, &create_parm
);
112 composite_continue_smb2(ctx
, req
, continue_unlink
, ctx
);
118 composite unlink call - sync interface
120 NTSTATUS
smb2_composite_unlink(struct smb2_tree
*tree
, union smb_unlink
*io
)
122 struct composite_context
*c
= smb2_composite_unlink_send(tree
, io
);
123 return composite_wait_free(c
);
130 continue after the create in a composite mkdir
132 static void continue_mkdir(struct smb2_request
*req
)
134 struct composite_context
*ctx
= talloc_get_type(req
->async
.private_data
,
135 struct composite_context
);
136 struct smb2_tree
*tree
= req
->tree
;
137 struct smb2_create create_parm
;
138 struct smb2_close close_parm
;
141 status
= smb2_create_recv(req
, ctx
, &create_parm
);
142 if (!NT_STATUS_IS_OK(status
)) {
143 composite_error(ctx
, status
);
147 ZERO_STRUCT(close_parm
);
148 close_parm
.in
.file
.handle
= create_parm
.out
.file
.handle
;
150 req
= smb2_close_send(tree
, &close_parm
);
151 composite_continue_smb2(ctx
, req
, continue_close
, ctx
);
155 composite SMB2 mkdir call
157 struct composite_context
*smb2_composite_mkdir_send(struct smb2_tree
*tree
,
160 struct composite_context
*ctx
;
161 struct smb2_create create_parm
;
162 struct smb2_request
*req
;
164 ctx
= composite_create(tree
, tree
->session
->transport
->ev
);
165 if (ctx
== NULL
) return NULL
;
167 ZERO_STRUCT(create_parm
);
169 create_parm
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
170 create_parm
.in
.share_access
=
171 NTCREATEX_SHARE_ACCESS_READ
|
172 NTCREATEX_SHARE_ACCESS_WRITE
;
173 create_parm
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
174 create_parm
.in
.file_attributes
= FILE_ATTRIBUTE_DIRECTORY
;
175 create_parm
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
176 create_parm
.in
.fname
= io
->mkdir
.in
.path
;
177 if (create_parm
.in
.fname
[0] == '\\') {
178 create_parm
.in
.fname
++;
181 req
= smb2_create_send(tree
, &create_parm
);
183 composite_continue_smb2(ctx
, req
, continue_mkdir
, ctx
);
190 composite mkdir call - sync interface
192 NTSTATUS
smb2_composite_mkdir(struct smb2_tree
*tree
, union smb_mkdir
*io
)
194 struct composite_context
*c
= smb2_composite_mkdir_send(tree
, io
);
195 return composite_wait_free(c
);
201 continue after the create in a composite rmdir
203 static void continue_rmdir(struct smb2_request
*req
)
205 struct composite_context
*ctx
= talloc_get_type(req
->async
.private_data
,
206 struct composite_context
);
207 struct smb2_tree
*tree
= req
->tree
;
208 struct smb2_create create_parm
;
209 struct smb2_close close_parm
;
212 status
= smb2_create_recv(req
, ctx
, &create_parm
);
213 if (!NT_STATUS_IS_OK(status
)) {
214 composite_error(ctx
, status
);
218 ZERO_STRUCT(close_parm
);
219 close_parm
.in
.file
.handle
= create_parm
.out
.file
.handle
;
221 req
= smb2_close_send(tree
, &close_parm
);
222 composite_continue_smb2(ctx
, req
, continue_close
, ctx
);
226 composite SMB2 rmdir call
228 struct composite_context
*smb2_composite_rmdir_send(struct smb2_tree
*tree
,
229 struct smb_rmdir
*io
)
231 struct composite_context
*ctx
;
232 struct smb2_create create_parm
;
233 struct smb2_request
*req
;
235 ctx
= composite_create(tree
, tree
->session
->transport
->ev
);
236 if (ctx
== NULL
) return NULL
;
238 ZERO_STRUCT(create_parm
);
239 create_parm
.in
.desired_access
= SEC_STD_DELETE
;
240 create_parm
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
241 create_parm
.in
.share_access
=
242 NTCREATEX_SHARE_ACCESS_DELETE
|
243 NTCREATEX_SHARE_ACCESS_READ
|
244 NTCREATEX_SHARE_ACCESS_WRITE
;
245 create_parm
.in
.create_options
=
246 NTCREATEX_OPTIONS_DIRECTORY
|
247 NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
248 create_parm
.in
.fname
= io
->in
.path
;
249 if (create_parm
.in
.fname
[0] == '\\') {
250 create_parm
.in
.fname
++;
253 req
= smb2_create_send(tree
, &create_parm
);
255 composite_continue_smb2(ctx
, req
, continue_rmdir
, ctx
);
261 composite rmdir call - sync interface
263 NTSTATUS
smb2_composite_rmdir(struct smb2_tree
*tree
, struct smb_rmdir
*io
)
265 struct composite_context
*c
= smb2_composite_rmdir_send(tree
, io
);
266 return composite_wait_free(c
);
269 struct smb2_composite_setpathinfo_state
{
270 struct smb2_tree
*tree
;
271 union smb_setfileinfo io
;
273 struct smb2_create cr
;
274 struct smb2_close cl
;
277 static void smb2_composite_setpathinfo_create_done(struct smb2_request
*smb2req
);
280 composite SMB2 setpathinfo call
282 struct tevent_req
*smb2_composite_setpathinfo_send(TALLOC_CTX
*mem_ctx
,
283 struct tevent_context
*ev
,
284 struct smb2_tree
*tree
,
285 const union smb_setfileinfo
*io
)
287 struct tevent_req
*req
;
288 struct smb2_composite_setpathinfo_state
*state
;
289 struct smb2_request
*smb2req
;
291 req
= tevent_req_create(mem_ctx
, &state
,
292 struct smb2_composite_setpathinfo_state
);
300 state
->cr
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
301 state
->cr
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
302 state
->cr
.in
.share_access
=
303 NTCREATEX_SHARE_ACCESS_DELETE
|
304 NTCREATEX_SHARE_ACCESS_READ
|
305 NTCREATEX_SHARE_ACCESS_WRITE
;
306 state
->cr
.in
.create_options
= 0;
307 state
->cr
.in
.fname
= state
->io
.generic
.in
.file
.path
;
308 if (state
->cr
.in
.fname
[0] == '\\') {
309 state
->cr
.in
.fname
++;
312 smb2req
= smb2_create_send(tree
, &state
->cr
);
313 if (tevent_req_nomem(smb2req
, req
)) {
314 return tevent_req_post(req
, ev
);
316 smb2req
->async
.fn
= smb2_composite_setpathinfo_create_done
;
317 smb2req
->async
.private_data
= req
;
322 static void smb2_composite_setpathinfo_setinfo_done(struct smb2_request
*smb2req
);
324 static void smb2_composite_setpathinfo_create_done(struct smb2_request
*smb2req
)
326 struct tevent_req
*req
=
327 talloc_get_type_abort(smb2req
->async
.private_data
,
329 struct smb2_composite_setpathinfo_state
*state
=
331 struct smb2_composite_setpathinfo_state
);
334 status
= smb2_create_recv(smb2req
, state
, &state
->cr
);
335 if (tevent_req_nterror(req
, status
)) {
339 state
->io
.generic
.in
.file
.handle
= state
->cr
.out
.file
.handle
;
341 smb2req
= smb2_setinfo_file_send(state
->tree
, &state
->io
);
342 if (tevent_req_nomem(smb2req
, req
)) {
345 smb2req
->async
.fn
= smb2_composite_setpathinfo_setinfo_done
;
346 smb2req
->async
.private_data
= req
;
349 static void smb2_composite_setpathinfo_close_done(struct smb2_request
*smb2req
);
351 static void smb2_composite_setpathinfo_setinfo_done(struct smb2_request
*smb2req
)
353 struct tevent_req
*req
=
354 talloc_get_type_abort(smb2req
->async
.private_data
,
356 struct smb2_composite_setpathinfo_state
*state
=
358 struct smb2_composite_setpathinfo_state
);
361 status
= smb2_setinfo_recv(smb2req
);
362 state
->set_status
= status
;
364 state
->cl
.in
.file
.handle
= state
->io
.generic
.in
.file
.handle
;
366 smb2req
= smb2_close_send(state
->tree
, &state
->cl
);
367 if (tevent_req_nomem(smb2req
, req
)) {
370 smb2req
->async
.fn
= smb2_composite_setpathinfo_close_done
;
371 smb2req
->async
.private_data
= req
;
374 static void smb2_composite_setpathinfo_close_done(struct smb2_request
*smb2req
)
376 struct tevent_req
*req
=
377 talloc_get_type_abort(smb2req
->async
.private_data
,
379 struct smb2_composite_setpathinfo_state
*state
=
381 struct smb2_composite_setpathinfo_state
);
384 status
= smb2_close_recv(smb2req
, &state
->cl
);
386 if (tevent_req_nterror(req
, state
->set_status
)) {
390 if (tevent_req_nterror(req
, status
)) {
394 tevent_req_done(req
);
397 NTSTATUS
smb2_composite_setpathinfo_recv(struct tevent_req
*req
)
401 if (tevent_req_is_nterror(req
, &status
)) {
402 tevent_req_received(req
);
406 tevent_req_received(req
);
411 composite setpathinfo call
413 NTSTATUS
smb2_composite_setpathinfo(struct smb2_tree
*tree
, union smb_setfileinfo
*io
)
415 struct tevent_req
*subreq
;
418 TALLOC_CTX
*frame
= talloc_stackframe();
419 struct tevent_context
*ev
= tree
->session
->transport
->ev
;
422 return NT_STATUS_NO_MEMORY
;
425 subreq
= smb2_composite_setpathinfo_send(frame
, ev
, tree
, io
);
426 if (subreq
== NULL
) {
428 return NT_STATUS_NO_MEMORY
;
431 ok
= tevent_req_poll(subreq
, ev
);
433 status
= map_nt_error_from_unix_common(errno
);
438 status
= smb2_composite_setpathinfo_recv(subreq
);
440 if (!NT_STATUS_IS_OK(status
)) {