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