2 Unix SMB/CIFS implementation.
4 SMB2 client utility functions
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "libcli/smb2/smb2.h"
26 #include "libcli/smb2/smb2_calls.h"
27 #include "libcli/smb_composite/smb_composite.h"
28 #include "librpc/gen_ndr/ndr_security.h"
31 simple close wrapper with SMB2
33 NTSTATUS
smb2_util_close(struct smb2_tree
*tree
, struct smb2_handle h
)
40 return smb2_close(tree
, &c
);
44 unlink a file with SMB2
46 NTSTATUS
smb2_util_unlink(struct smb2_tree
*tree
, const char *fname
)
51 io
.unlink
.in
.pattern
= fname
;
53 return smb2_composite_unlink(tree
, &io
);
60 NTSTATUS
smb2_util_rmdir(struct smb2_tree
*tree
, const char *dname
)
67 return smb2_composite_rmdir(tree
, &io
);
74 NTSTATUS
smb2_util_mkdir(struct smb2_tree
*tree
, const char *dname
)
79 io
.mkdir
.level
= RAW_MKDIR_MKDIR
;
80 io
.mkdir
.in
.path
= dname
;
82 return smb2_composite_mkdir(tree
, &io
);
87 set file attribute with SMB2
89 NTSTATUS
smb2_util_setatr(struct smb2_tree
*tree
, const char *name
, uint32_t attrib
)
91 struct smb2_create cr
= {0};
92 struct smb2_handle h1
= {{0}};
93 union smb_setfileinfo setinfo
;
96 cr
= (struct smb2_create
) {
97 .in
.desired_access
= SEC_FILE_WRITE_ATTRIBUTE
,
98 .in
.share_access
= NTCREATEX_SHARE_ACCESS_MASK
,
99 .in
.create_disposition
= FILE_OPEN
,
102 status
= smb2_create(tree
, tree
, &cr
);
103 if (!NT_STATUS_IS_OK(status
)) {
106 h1
= cr
.out
.file
.handle
;
108 setinfo
= (union smb_setfileinfo
) {
109 .basic_info
.level
= RAW_SFILEINFO_BASIC_INFORMATION
,
110 .basic_info
.in
.file
.handle
= h1
,
111 .basic_info
.in
.attrib
= attrib
,
114 status
= smb2_setinfo_file(tree
, &setinfo
);
115 if (!NT_STATUS_IS_OK(status
)) {
116 smb2_util_close(tree
, h1
);
120 smb2_util_close(tree
, h1
);
126 get file attribute with SMB2
128 NTSTATUS
smb2_util_getatr(struct smb2_tree
*tree
, const char *fname
,
129 uint16_t *attr
, size_t *size
, time_t *t
)
131 union smb_fileinfo parms
;
133 struct smb2_create create_io
= {0};
135 create_io
.in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
;
136 create_io
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
137 create_io
.in
.create_disposition
= FILE_OPEN
;
138 create_io
.in
.fname
= fname
;
139 status
= smb2_create(tree
, tree
, &create_io
);
140 if (!NT_STATUS_IS_OK(status
)) {
145 parms
.all_info2
.level
= RAW_FILEINFO_SMB2_ALL_INFORMATION
;
146 parms
.all_info2
.in
.file
.handle
= create_io
.out
.file
.handle
;
147 status
= smb2_getinfo_file(tree
, tree
, &parms
);
148 if (!NT_STATUS_IS_OK(status
)) {
152 status
= smb2_util_close(tree
, create_io
.out
.file
.handle
);
153 if (!NT_STATUS_IS_OK(status
)) {
158 *size
= parms
.all_info2
.out
.size
;
162 *t
= parms
.all_info2
.out
.write_time
;
166 *attr
= parms
.all_info2
.out
.attrib
;
174 recursively descend a tree deleting all files
175 returns the number of files deleted, or -1 on error
177 int smb2_deltree(struct smb2_tree
*tree
, const char *dname
)
180 uint32_t total_deleted
= 0;
181 unsigned int count
, i
;
182 union smb_search_data
*list
;
183 TALLOC_CTX
*tmp_ctx
= talloc_new(tree
);
185 struct smb2_create create_parm
;
188 /* it might be a file */
189 status
= smb2_util_unlink(tree
, dname
);
190 if (NT_STATUS_IS_OK(status
)) {
191 talloc_free(tmp_ctx
);
194 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
) ||
195 NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_PATH_NOT_FOUND
) ||
196 NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_FILE
)) {
197 talloc_free(tmp_ctx
);
201 if (NT_STATUS_EQUAL(status
, NT_STATUS_CANNOT_DELETE
)) {
202 /* it could be read-only */
203 smb2_util_setatr(tree
, dname
, FILE_ATTRIBUTE_NORMAL
);
204 status
= smb2_util_unlink(tree
, dname
);
206 if (NT_STATUS_IS_OK(status
)) {
207 talloc_free(tmp_ctx
);
211 ZERO_STRUCT(create_parm
);
212 create_parm
.in
.desired_access
= SEC_FILE_READ_DATA
;
213 create_parm
.in
.share_access
=
214 NTCREATEX_SHARE_ACCESS_READ
|
215 NTCREATEX_SHARE_ACCESS_WRITE
;
216 create_parm
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
217 create_parm
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
218 create_parm
.in
.fname
= dname
;
220 status
= smb2_create(tree
, tmp_ctx
, &create_parm
);
221 if (NT_STATUS_IS_ERR(status
)) {
222 DEBUG(2,("Failed to open %s - %s\n", dname
, nt_errstr(status
)));
223 talloc_free(tmp_ctx
);
232 f
.in
.file
.handle
= create_parm
.out
.file
.handle
;
233 f
.in
.max_response_size
= 0x10000;
234 f
.in
.level
= SMB2_FIND_NAME_INFO
;
237 status
= smb2_find_level(tree
, tmp_ctx
, &f
, &count
, &list
);
238 if (NT_STATUS_IS_ERR(status
)) {
239 DEBUG(2,("Failed to list %s - %s\n",
240 dname
, nt_errstr(status
)));
241 smb2_util_close(tree
, create_parm
.out
.file
.handle
);
242 talloc_free(tmp_ctx
);
246 for (i
=0;i
<count
;i
++) {
248 if (strcmp(".", list
[i
].name_info
.name
.s
) == 0 ||
249 strcmp("..", list
[i
].name_info
.name
.s
) == 0) {
252 name
= talloc_asprintf(tmp_ctx
, "%s\\%s", dname
, list
[i
].name_info
.name
.s
);
253 status
= smb2_util_unlink(tree
, name
);
254 if (NT_STATUS_EQUAL(status
, NT_STATUS_CANNOT_DELETE
)) {
255 /* it could be read-only */
256 smb2_util_setatr(tree
, name
, FILE_ATTRIBUTE_NORMAL
);
257 status
= smb2_util_unlink(tree
, name
);
260 if (NT_STATUS_EQUAL(status
, NT_STATUS_FILE_IS_A_DIRECTORY
)) {
262 ret
= smb2_deltree(tree
, name
);
263 if (ret
> 0) total_deleted
+= ret
;
266 if (NT_STATUS_IS_OK(status
)) {
271 } while (did_delete
);
273 smb2_util_close(tree
, create_parm
.out
.file
.handle
);
275 status
= smb2_util_rmdir(tree
, dname
);
276 if (NT_STATUS_EQUAL(status
, NT_STATUS_CANNOT_DELETE
)) {
277 /* it could be read-only */
278 smb2_util_setatr(tree
, dname
, FILE_ATTRIBUTE_NORMAL
);
279 status
= smb2_util_rmdir(tree
, dname
);
282 if (NT_STATUS_IS_ERR(status
)) {
283 DEBUG(2,("Failed to delete %s - %s\n",
284 dname
, nt_errstr(status
)));
285 talloc_free(tmp_ctx
);
289 talloc_free(tmp_ctx
);
291 return total_deleted
;
295 check if two SMB2 file handles are the same
297 bool smb2_util_handle_equal(const struct smb2_handle h1
,
298 const struct smb2_handle h2
)
300 return (h1
.data
[0] == h2
.data
[0]) && (h1
.data
[1] == h2
.data
[1]);
303 bool smb2_util_handle_empty(const struct smb2_handle h
)
305 struct smb2_handle empty
;
309 return smb2_util_handle_equal(h
, empty
);
312 /****************************************************************************
313 send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
314 ****************************************************************************/
315 NTSTATUS
smb2_qpathinfo_alt_name(TALLOC_CTX
*ctx
, struct smb2_tree
*tree
,
316 const char *fname
, const char **alt_name
)
318 union smb_fileinfo parms
;
321 struct smb2_create create_io
= {0};
323 mem_ctx
= talloc_new(ctx
);
325 return NT_STATUS_NO_MEMORY
;
328 create_io
.in
.desired_access
= SEC_FILE_READ_ATTRIBUTE
;
329 create_io
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
330 create_io
.in
.create_disposition
= FILE_OPEN
;
331 create_io
.in
.fname
= fname
;
332 status
= smb2_create(tree
, mem_ctx
, &create_io
);
333 if (!NT_STATUS_IS_OK(status
)) {
334 talloc_free(mem_ctx
);
338 parms
.alt_name_info
.level
= RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION
;
339 parms
.alt_name_info
.in
.file
.handle
= create_io
.out
.file
.handle
;
341 status
= smb2_getinfo_file(tree
, mem_ctx
, &parms
);
342 if (!NT_STATUS_IS_OK(status
)) {
343 talloc_free(mem_ctx
);
347 status
= smb2_util_close(tree
, create_io
.out
.file
.handle
);
348 if (!NT_STATUS_IS_OK(status
)) {
349 talloc_free(mem_ctx
);
353 if (!parms
.alt_name_info
.out
.fname
.s
) {
354 *alt_name
= talloc_strdup(ctx
, "");
356 *alt_name
= talloc_strdup(ctx
,
357 parms
.alt_name_info
.out
.fname
.s
);
360 talloc_free(mem_ctx
);