Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : SMB2 client utility functions
5 :
6 : Copyright (C) Andrew Tridgell 2005
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
22 : #include "includes.h"
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"
29 :
30 : /*
31 : simple close wrapper with SMB2
32 : */
33 219884 : NTSTATUS smb2_util_close(struct smb2_tree *tree, struct smb2_handle h)
34 : {
35 126 : struct smb2_close c;
36 :
37 219884 : ZERO_STRUCT(c);
38 219884 : c.in.file.handle = h;
39 :
40 219884 : return smb2_close(tree, &c);
41 : }
42 :
43 : /*
44 : unlink a file with SMB2
45 : */
46 358783 : NTSTATUS smb2_util_unlink(struct smb2_tree *tree, const char *fname)
47 : {
48 188 : union smb_unlink io;
49 :
50 358783 : ZERO_STRUCT(io);
51 358783 : io.unlink.in.pattern = fname;
52 :
53 358783 : return smb2_composite_unlink(tree, &io);
54 : }
55 :
56 :
57 : /*
58 : rmdir with SMB2
59 : */
60 2492 : NTSTATUS smb2_util_rmdir(struct smb2_tree *tree, const char *dname)
61 : {
62 2 : struct smb_rmdir io;
63 :
64 2492 : ZERO_STRUCT(io);
65 2492 : io.in.path = dname;
66 :
67 2492 : return smb2_composite_rmdir(tree, &io);
68 : }
69 :
70 :
71 : /*
72 : mkdir with SMB2
73 : */
74 391 : NTSTATUS smb2_util_mkdir(struct smb2_tree *tree, const char *dname)
75 : {
76 2 : union smb_mkdir io;
77 :
78 391 : ZERO_STRUCT(io);
79 391 : io.mkdir.level = RAW_MKDIR_MKDIR;
80 391 : io.mkdir.in.path = dname;
81 :
82 391 : return smb2_composite_mkdir(tree, &io);
83 : }
84 :
85 :
86 : /*
87 : set file attribute with SMB2
88 : */
89 88 : NTSTATUS smb2_util_setatr(struct smb2_tree *tree, const char *name, uint32_t attrib)
90 : {
91 88 : struct smb2_create cr = {0};
92 88 : struct smb2_handle h1 = {{0}};
93 0 : union smb_setfileinfo setinfo;
94 0 : NTSTATUS status;
95 :
96 88 : 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,
100 : .in.fname = name,
101 : };
102 88 : status = smb2_create(tree, tree, &cr);
103 88 : if (!NT_STATUS_IS_OK(status)) {
104 64 : return status;
105 : }
106 24 : h1 = cr.out.file.handle;
107 :
108 24 : 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,
112 : };
113 :
114 24 : status = smb2_setinfo_file(tree, &setinfo);
115 24 : if (!NT_STATUS_IS_OK(status)) {
116 0 : smb2_util_close(tree, h1);
117 0 : return status;
118 : }
119 :
120 24 : smb2_util_close(tree, h1);
121 24 : return NT_STATUS_OK;
122 : }
123 :
124 :
125 : /*
126 : get file attribute with SMB2
127 : */
128 515 : NTSTATUS smb2_util_getatr(struct smb2_tree *tree, const char *fname,
129 : uint16_t *attr, size_t *size, time_t *t)
130 : {
131 0 : union smb_fileinfo parms;
132 0 : NTSTATUS status;
133 515 : struct smb2_create create_io = {0};
134 :
135 515 : create_io.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
136 515 : create_io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
137 515 : create_io.in.create_disposition = FILE_OPEN;
138 515 : create_io.in.fname = fname;
139 515 : status = smb2_create(tree, tree, &create_io);
140 515 : if (!NT_STATUS_IS_OK(status)) {
141 0 : return status;
142 : }
143 :
144 515 : ZERO_STRUCT(parms);
145 515 : parms.all_info2.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
146 515 : parms.all_info2.in.file.handle = create_io.out.file.handle;
147 515 : status = smb2_getinfo_file(tree, tree, &parms);
148 515 : if (!NT_STATUS_IS_OK(status)) {
149 0 : return status;
150 : }
151 :
152 515 : status = smb2_util_close(tree, create_io.out.file.handle);
153 515 : if (!NT_STATUS_IS_OK(status)) {
154 0 : return status;
155 : }
156 :
157 515 : if (size) {
158 0 : *size = parms.all_info2.out.size;
159 : }
160 :
161 515 : if (t) {
162 0 : *t = parms.all_info2.out.write_time;
163 : }
164 :
165 515 : if (attr) {
166 515 : *attr = parms.all_info2.out.attrib;
167 : }
168 :
169 515 : return status;
170 : }
171 :
172 :
173 : /*
174 : recursively descend a tree deleting all files
175 : returns the number of files deleted, or -1 on error
176 : */
177 3286 : int smb2_deltree(struct smb2_tree *tree, const char *dname)
178 : {
179 4 : NTSTATUS status;
180 3286 : uint32_t total_deleted = 0;
181 4 : unsigned int count, i;
182 4 : union smb_search_data *list;
183 3286 : TALLOC_CTX *tmp_ctx = talloc_new(tree);
184 4 : struct smb2_find f;
185 4 : struct smb2_create create_parm;
186 4 : bool did_delete;
187 :
188 : /* it might be a file */
189 3286 : status = smb2_util_unlink(tree, dname);
190 3286 : if (NT_STATUS_IS_OK(status)) {
191 101 : talloc_free(tmp_ctx);
192 101 : return 1;
193 : }
194 3185 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
195 2082 : NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
196 2049 : NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_FILE)) {
197 1134 : talloc_free(tmp_ctx);
198 1134 : return 0;
199 : }
200 :
201 2049 : if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
202 : /* it could be read-only */
203 6 : smb2_util_setatr(tree, dname, FILE_ATTRIBUTE_NORMAL);
204 6 : status = smb2_util_unlink(tree, dname);
205 : }
206 2051 : if (NT_STATUS_IS_OK(status)) {
207 6 : talloc_free(tmp_ctx);
208 6 : return 1;
209 : }
210 :
211 2045 : ZERO_STRUCT(create_parm);
212 2045 : create_parm.in.desired_access = SEC_FILE_READ_DATA;
213 2045 : create_parm.in.share_access =
214 : NTCREATEX_SHARE_ACCESS_READ|
215 : NTCREATEX_SHARE_ACCESS_WRITE;
216 2045 : create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
217 2045 : create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
218 2045 : create_parm.in.fname = dname;
219 :
220 2045 : status = smb2_create(tree, tmp_ctx, &create_parm);
221 2045 : if (NT_STATUS_IS_ERR(status)) {
222 151 : DEBUG(2,("Failed to open %s - %s\n", dname, nt_errstr(status)));
223 151 : talloc_free(tmp_ctx);
224 151 : return -1;
225 : }
226 :
227 :
228 2 : do {
229 2680 : did_delete = false;
230 :
231 2680 : ZERO_STRUCT(f);
232 2680 : f.in.file.handle = create_parm.out.file.handle;
233 2680 : f.in.max_response_size = 0x10000;
234 2680 : f.in.level = SMB2_FIND_NAME_INFO;
235 2680 : f.in.pattern = "*";
236 :
237 2680 : status = smb2_find_level(tree, tmp_ctx, &f, &count, &list);
238 2680 : if (NT_STATUS_IS_ERR(status)) {
239 0 : DEBUG(2,("Failed to list %s - %s\n",
240 : dname, nt_errstr(status)));
241 0 : smb2_util_close(tree, create_parm.out.file.handle);
242 0 : talloc_free(tmp_ctx);
243 0 : return -1;
244 : }
245 :
246 355038 : for (i=0;i<count;i++) {
247 6 : char *name;
248 352358 : if (strcmp(".", list[i].name_info.name.s) == 0 ||
249 349730 : strcmp("..", list[i].name_info.name.s) == 0) {
250 5256 : continue;
251 : }
252 347102 : name = talloc_asprintf(tmp_ctx, "%s\\%s", dname, list[i].name_info.name.s);
253 347102 : status = smb2_util_unlink(tree, name);
254 347102 : if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
255 : /* it could be read-only */
256 9 : smb2_util_setatr(tree, name, FILE_ATTRIBUTE_NORMAL);
257 9 : status = smb2_util_unlink(tree, name);
258 : }
259 :
260 347102 : if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
261 0 : int ret;
262 775 : ret = smb2_deltree(tree, name);
263 775 : if (ret > 0) total_deleted += ret;
264 : }
265 347102 : talloc_free(name);
266 347102 : if (NT_STATUS_IS_OK(status)) {
267 193193 : total_deleted++;
268 193193 : did_delete = true;
269 : }
270 : }
271 2680 : } while (did_delete);
272 :
273 1894 : smb2_util_close(tree, create_parm.out.file.handle);
274 :
275 1894 : status = smb2_util_rmdir(tree, dname);
276 1894 : if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
277 : /* it could be read-only */
278 0 : smb2_util_setatr(tree, dname, FILE_ATTRIBUTE_NORMAL);
279 0 : status = smb2_util_rmdir(tree, dname);
280 : }
281 :
282 1894 : if (NT_STATUS_IS_ERR(status)) {
283 76 : DEBUG(2,("Failed to delete %s - %s\n",
284 : dname, nt_errstr(status)));
285 76 : talloc_free(tmp_ctx);
286 76 : return -1;
287 : }
288 :
289 1818 : talloc_free(tmp_ctx);
290 :
291 1818 : return total_deleted;
292 : }
293 :
294 : /*
295 : check if two SMB2 file handles are the same
296 : */
297 816 : bool smb2_util_handle_equal(const struct smb2_handle h1,
298 : const struct smb2_handle h2)
299 : {
300 816 : return (h1.data[0] == h2.data[0]) && (h1.data[1] == h2.data[1]);
301 : }
302 :
303 816 : bool smb2_util_handle_empty(const struct smb2_handle h)
304 : {
305 0 : struct smb2_handle empty;
306 :
307 816 : ZERO_STRUCT(empty);
308 :
309 816 : return smb2_util_handle_equal(h, empty);
310 : }
311 :
312 : /****************************************************************************
313 : send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
314 : ****************************************************************************/
315 50 : NTSTATUS smb2_qpathinfo_alt_name(TALLOC_CTX *ctx, struct smb2_tree *tree,
316 : const char *fname, const char **alt_name)
317 : {
318 0 : union smb_fileinfo parms;
319 0 : TALLOC_CTX *mem_ctx;
320 0 : NTSTATUS status;
321 50 : struct smb2_create create_io = {0};
322 :
323 50 : mem_ctx = talloc_new(ctx);
324 50 : if (!mem_ctx) {
325 0 : return NT_STATUS_NO_MEMORY;
326 : }
327 :
328 50 : create_io.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
329 50 : create_io.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
330 50 : create_io.in.create_disposition = FILE_OPEN;
331 50 : create_io.in.fname = fname;
332 50 : status = smb2_create(tree, mem_ctx, &create_io);
333 50 : if (!NT_STATUS_IS_OK(status)) {
334 0 : talloc_free(mem_ctx);
335 0 : return status;
336 : }
337 :
338 50 : parms.alt_name_info.level = RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION;
339 50 : parms.alt_name_info.in.file.handle = create_io.out.file.handle;
340 :
341 50 : status = smb2_getinfo_file(tree, mem_ctx, &parms);
342 50 : if (!NT_STATUS_IS_OK(status)) {
343 0 : talloc_free(mem_ctx);
344 0 : return status;
345 : }
346 :
347 50 : status = smb2_util_close(tree, create_io.out.file.handle);
348 50 : if (!NT_STATUS_IS_OK(status)) {
349 0 : talloc_free(mem_ctx);
350 0 : return status;
351 : }
352 :
353 50 : if (!parms.alt_name_info.out.fname.s) {
354 0 : *alt_name = talloc_strdup(ctx, "");
355 : } else {
356 50 : *alt_name = talloc_strdup(ctx,
357 : parms.alt_name_info.out.fname.s);
358 : }
359 :
360 50 : talloc_free(mem_ctx);
361 :
362 50 : return NT_STATUS_OK;
363 : }
|