Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : POSIX NTVFS backend - read
5 :
6 : Copyright (C) Andrew Tridgell 2004
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 "vfs_posix.h"
24 : #include "librpc/gen_ndr/xattr.h"
25 :
26 :
27 : /*
28 : determine what access bits are needed for a call
29 : */
30 11289 : static uint32_t pvfs_fileinfo_access(union smb_fileinfo *info)
31 : {
32 0 : uint32_t needed;
33 :
34 11289 : switch (info->generic.level) {
35 18 : case RAW_FILEINFO_EA_LIST:
36 : case RAW_FILEINFO_ALL_EAS:
37 18 : needed = SEC_FILE_READ_EA;
38 18 : break;
39 :
40 7 : case RAW_FILEINFO_IS_NAME_VALID:
41 7 : needed = 0;
42 7 : break;
43 :
44 74 : case RAW_FILEINFO_ACCESS_INFORMATION:
45 74 : needed = 0;
46 74 : break;
47 :
48 42 : case RAW_FILEINFO_STREAM_INFO:
49 : case RAW_FILEINFO_STREAM_INFORMATION:
50 42 : needed = 0;
51 42 : break;
52 :
53 639 : case RAW_FILEINFO_SEC_DESC:
54 639 : needed = 0;
55 639 : if (info->query_secdesc.in.secinfo_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
56 421 : needed |= SEC_STD_READ_CONTROL;
57 : }
58 639 : if (info->query_secdesc.in.secinfo_flags & SECINFO_DACL) {
59 638 : needed |= SEC_STD_READ_CONTROL;
60 : }
61 639 : if (info->query_secdesc.in.secinfo_flags & SECINFO_SACL) {
62 0 : needed |= SEC_FLAG_SYSTEM_SECURITY;
63 : }
64 639 : break;
65 :
66 10509 : default:
67 10509 : needed = SEC_FILE_READ_ATTRIBUTE;
68 10509 : break;
69 : }
70 :
71 11289 : return needed;
72 : }
73 :
74 : /*
75 : reply to a RAW_FILEINFO_EA_LIST call
76 : */
77 10 : NTSTATUS pvfs_query_ea_list(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
78 : struct pvfs_filename *name, int fd,
79 : unsigned int num_names,
80 : struct ea_name *names,
81 : struct smb_ea_list *eas)
82 : {
83 0 : NTSTATUS status;
84 0 : int i;
85 10 : struct xattr_DosEAs *ealist = talloc(mem_ctx, struct xattr_DosEAs);
86 :
87 10 : ZERO_STRUCTP(eas);
88 10 : status = pvfs_doseas_load(pvfs, name, fd, ealist);
89 10 : if (!NT_STATUS_IS_OK(status)) {
90 1 : return status;
91 : }
92 9 : eas->eas = talloc_array(mem_ctx, struct ea_struct, num_names);
93 9 : if (eas->eas == NULL) {
94 0 : return NT_STATUS_NO_MEMORY;
95 : }
96 9 : eas->num_eas = num_names;
97 21 : for (i=0;i<num_names;i++) {
98 0 : int j;
99 12 : eas->eas[i].flags = 0;
100 12 : eas->eas[i].name.s = names[i].name.s;
101 12 : eas->eas[i].value = data_blob(NULL, 0);
102 24 : for (j=0;j<ealist->num_eas;j++) {
103 20 : if (strcasecmp_m(eas->eas[i].name.s,
104 20 : ealist->eas[j].name) == 0) {
105 8 : if (ealist->eas[j].value.length == 0) {
106 0 : continue;
107 : }
108 8 : eas->eas[i].value = ealist->eas[j].value;
109 8 : break;
110 : }
111 : }
112 : }
113 9 : return NT_STATUS_OK;
114 : }
115 :
116 : /*
117 : reply to a RAW_FILEINFO_ALL_EAS call
118 : */
119 17 : static NTSTATUS pvfs_query_all_eas(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
120 : struct pvfs_filename *name, int fd,
121 : struct smb_ea_list *eas)
122 : {
123 0 : NTSTATUS status;
124 0 : int i;
125 17 : struct xattr_DosEAs *ealist = talloc(mem_ctx, struct xattr_DosEAs);
126 :
127 17 : ZERO_STRUCTP(eas);
128 17 : status = pvfs_doseas_load(pvfs, name, fd, ealist);
129 17 : if (!NT_STATUS_IS_OK(status)) {
130 1 : return status;
131 : }
132 16 : eas->eas = talloc_array(mem_ctx, struct ea_struct, ealist->num_eas);
133 16 : if (eas->eas == NULL) {
134 0 : return NT_STATUS_NO_MEMORY;
135 : }
136 16 : eas->num_eas = 0;
137 37 : for (i=0;i<ealist->num_eas;i++) {
138 21 : eas->eas[eas->num_eas].flags = 0;
139 21 : eas->eas[eas->num_eas].name.s = ealist->eas[i].name;
140 21 : if (ealist->eas[i].value.length == 0) {
141 0 : continue;
142 : }
143 21 : eas->eas[eas->num_eas].value = ealist->eas[i].value;
144 21 : eas->num_eas++;
145 : }
146 16 : return NT_STATUS_OK;
147 : }
148 :
149 : /*
150 : approximately map a struct pvfs_filename to a generic fileinfo struct
151 : */
152 11288 : static NTSTATUS pvfs_map_fileinfo(struct pvfs_state *pvfs,
153 : struct ntvfs_request *req,
154 : struct pvfs_filename *name, union smb_fileinfo *info,
155 : int fd)
156 : {
157 11288 : switch (info->generic.level) {
158 552 : case RAW_FILEINFO_GETATTR:
159 552 : info->getattr.out.attrib = name->dos.attrib;
160 552 : info->getattr.out.size = name->st.st_size;
161 552 : info->getattr.out.write_time = nt_time_to_unix(name->dos.write_time);
162 552 : return NT_STATUS_OK;
163 :
164 147 : case RAW_FILEINFO_GETATTRE:
165 : case RAW_FILEINFO_STANDARD:
166 147 : info->standard.out.create_time = nt_time_to_unix(name->dos.create_time);
167 147 : info->standard.out.access_time = nt_time_to_unix(name->dos.access_time);
168 147 : info->standard.out.write_time = nt_time_to_unix(name->dos.write_time);
169 147 : info->standard.out.size = name->st.st_size;
170 147 : info->standard.out.alloc_size = name->dos.alloc_size;
171 147 : info->standard.out.attrib = name->dos.attrib;
172 147 : return NT_STATUS_OK;
173 :
174 6 : case RAW_FILEINFO_EA_SIZE:
175 6 : info->ea_size.out.create_time = nt_time_to_unix(name->dos.create_time);
176 6 : info->ea_size.out.access_time = nt_time_to_unix(name->dos.access_time);
177 6 : info->ea_size.out.write_time = nt_time_to_unix(name->dos.write_time);
178 6 : info->ea_size.out.size = name->st.st_size;
179 6 : info->ea_size.out.alloc_size = name->dos.alloc_size;
180 6 : info->ea_size.out.attrib = name->dos.attrib;
181 6 : info->ea_size.out.ea_size = name->dos.ea_size;
182 6 : return NT_STATUS_OK;
183 :
184 7 : case RAW_FILEINFO_EA_LIST:
185 7 : return pvfs_query_ea_list(pvfs, req, name, fd,
186 : info->ea_list.in.num_names,
187 : info->ea_list.in.ea_names,
188 : &info->ea_list.out);
189 :
190 11 : case RAW_FILEINFO_ALL_EAS:
191 11 : return pvfs_query_all_eas(pvfs, req, name, fd, &info->all_eas.out);
192 :
193 6 : case RAW_FILEINFO_SMB2_ALL_EAS: {
194 6 : NTSTATUS status = pvfs_query_all_eas(pvfs, req, name, fd, &info->all_eas.out);
195 6 : if (NT_STATUS_IS_OK(status) &&
196 6 : info->all_eas.out.num_eas == 0) {
197 2 : return NT_STATUS_NO_EAS_ON_FILE;
198 : }
199 4 : return status;
200 : }
201 :
202 7 : case RAW_FILEINFO_IS_NAME_VALID:
203 7 : return NT_STATUS_OK;
204 :
205 353 : case RAW_FILEINFO_BASIC_INFO:
206 : case RAW_FILEINFO_BASIC_INFORMATION:
207 353 : info->basic_info.out.create_time = name->dos.create_time;
208 353 : info->basic_info.out.access_time = name->dos.access_time;
209 353 : info->basic_info.out.write_time = name->dos.write_time;
210 353 : info->basic_info.out.change_time = name->dos.change_time;
211 353 : info->basic_info.out.attrib = name->dos.attrib;
212 353 : return NT_STATUS_OK;
213 :
214 179 : case RAW_FILEINFO_STANDARD_INFO:
215 : case RAW_FILEINFO_STANDARD_INFORMATION:
216 179 : info->standard_info.out.alloc_size = name->dos.alloc_size;
217 179 : info->standard_info.out.size = name->st.st_size;
218 179 : info->standard_info.out.nlink = name->dos.nlink;
219 179 : info->standard_info.out.delete_pending = 0; /* only for qfileinfo */
220 179 : info->standard_info.out.directory =
221 179 : (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)? 1 : 0;
222 179 : return NT_STATUS_OK;
223 :
224 18 : case RAW_FILEINFO_EA_INFO:
225 : case RAW_FILEINFO_EA_INFORMATION:
226 18 : info->ea_info.out.ea_size = name->dos.ea_size;
227 18 : return NT_STATUS_OK;
228 :
229 57 : case RAW_FILEINFO_NAME_INFO:
230 : case RAW_FILEINFO_NAME_INFORMATION:
231 57 : if (req->ctx->protocol >= PROTOCOL_SMB2_02) {
232 : /* strange that SMB2 doesn't have this */
233 0 : return NT_STATUS_NOT_SUPPORTED;
234 : }
235 57 : info->name_info.out.fname.s = name->original_name;
236 57 : return NT_STATUS_OK;
237 :
238 522 : case RAW_FILEINFO_ALL_INFO:
239 : case RAW_FILEINFO_ALL_INFORMATION:
240 522 : info->all_info.out.create_time = name->dos.create_time;
241 522 : info->all_info.out.access_time = name->dos.access_time;
242 522 : info->all_info.out.write_time = name->dos.write_time;
243 522 : info->all_info.out.change_time = name->dos.change_time;
244 522 : info->all_info.out.attrib = name->dos.attrib;
245 522 : info->all_info.out.alloc_size = name->dos.alloc_size;
246 522 : info->all_info.out.size = name->st.st_size;
247 522 : info->all_info.out.nlink = name->dos.nlink;
248 522 : info->all_info.out.delete_pending = 0; /* only set by qfileinfo */
249 522 : info->all_info.out.directory =
250 522 : (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)? 1 : 0;
251 522 : info->all_info.out.ea_size = name->dos.ea_size;
252 522 : info->all_info.out.fname.s = name->original_name;
253 522 : return NT_STATUS_OK;
254 :
255 52 : case RAW_FILEINFO_ALT_NAME_INFO:
256 : case RAW_FILEINFO_ALT_NAME_INFORMATION:
257 : case RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION:
258 52 : info->name_info.out.fname.s = pvfs_short_name(pvfs, name, name);
259 52 : return NT_STATUS_OK;
260 :
261 42 : case RAW_FILEINFO_STREAM_INFO:
262 : case RAW_FILEINFO_STREAM_INFORMATION:
263 42 : return pvfs_stream_information(pvfs, req, name, fd, &info->stream_info.out);
264 :
265 16 : case RAW_FILEINFO_COMPRESSION_INFO:
266 : case RAW_FILEINFO_COMPRESSION_INFORMATION:
267 16 : info->compression_info.out.compressed_size = name->st.st_size;
268 16 : info->compression_info.out.format = 0;
269 16 : info->compression_info.out.unit_shift = 0;
270 16 : info->compression_info.out.chunk_shift = 0;
271 16 : info->compression_info.out.cluster_shift = 0;
272 16 : return NT_STATUS_OK;
273 :
274 21 : case RAW_FILEINFO_INTERNAL_INFORMATION:
275 21 : info->internal_information.out.file_id = name->dos.file_id;
276 21 : return NT_STATUS_OK;
277 :
278 74 : case RAW_FILEINFO_ACCESS_INFORMATION:
279 74 : info->access_information.out.access_flags = 0; /* only set by qfileinfo */
280 74 : return NT_STATUS_OK;
281 :
282 26 : case RAW_FILEINFO_POSITION_INFORMATION:
283 26 : info->position_information.out.position = 0; /* only set by qfileinfo */
284 26 : return NT_STATUS_OK;
285 :
286 18 : case RAW_FILEINFO_MODE_INFORMATION:
287 18 : info->mode_information.out.mode = 0; /* only set by qfileinfo */
288 18 : return NT_STATUS_OK;
289 :
290 12 : case RAW_FILEINFO_ALIGNMENT_INFORMATION:
291 12 : info->alignment_information.out.alignment_requirement = 0;
292 12 : return NT_STATUS_OK;
293 :
294 6 : case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
295 6 : info->network_open_information.out.create_time = name->dos.create_time;
296 6 : info->network_open_information.out.access_time = name->dos.access_time;
297 6 : info->network_open_information.out.write_time = name->dos.write_time;
298 6 : info->network_open_information.out.change_time = name->dos.change_time;
299 6 : info->network_open_information.out.alloc_size = name->dos.alloc_size;
300 6 : info->network_open_information.out.size = name->st.st_size;
301 6 : info->network_open_information.out.attrib = name->dos.attrib;
302 6 : return NT_STATUS_OK;
303 :
304 6 : case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
305 6 : info->attribute_tag_information.out.attrib = name->dos.attrib;
306 6 : info->attribute_tag_information.out.reparse_tag = 0;
307 6 : return NT_STATUS_OK;
308 :
309 639 : case RAW_FILEINFO_SEC_DESC:
310 639 : return pvfs_acl_query(pvfs, req, name, fd, info);
311 :
312 618 : case RAW_FILEINFO_SMB2_ALL_INFORMATION:
313 618 : info->all_info2.out.create_time = name->dos.create_time;
314 618 : info->all_info2.out.access_time = name->dos.access_time;
315 618 : info->all_info2.out.write_time = name->dos.write_time;
316 618 : info->all_info2.out.change_time = name->dos.change_time;
317 618 : info->all_info2.out.attrib = name->dos.attrib;
318 618 : info->all_info2.out.unknown1 = 0;
319 618 : info->all_info2.out.alloc_size = name->dos.alloc_size;
320 618 : info->all_info2.out.size = name->st.st_size;
321 618 : info->all_info2.out.nlink = name->dos.nlink;
322 618 : info->all_info2.out.delete_pending = 0; /* only set by qfileinfo */
323 618 : info->all_info2.out.directory =
324 618 : (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)? 1 : 0;
325 618 : info->all_info2.out.file_id = name->dos.file_id;
326 618 : info->all_info2.out.ea_size = name->dos.ea_size;
327 618 : info->all_info2.out.access_mask = 0; /* only set by qfileinfo */
328 618 : info->all_info2.out.position = 0; /* only set by qfileinfo */
329 618 : info->all_info2.out.mode = 0; /* only set by qfileinfo */
330 618 : info->all_info2.out.alignment_requirement = 0;
331 : /* windows wants the full path on disk for this
332 : result, but I really don't want to expose that on
333 : the wire, so I'll give the path with a share
334 : prefix, which is a good approximation */
335 618 : info->all_info2.out.fname.s = talloc_asprintf(req, "\\%s\\%s",
336 : pvfs->share_name,
337 : name->original_name);
338 618 : NT_STATUS_HAVE_NO_MEMORY(info->all_info2.out.fname.s);
339 618 : return NT_STATUS_OK;
340 :
341 16 : case RAW_FILEINFO_GENERIC:
342 : case RAW_FILEINFO_UNIX_BASIC:
343 : case RAW_FILEINFO_UNIX_INFO2:
344 : case RAW_FILEINFO_UNIX_LINK:
345 16 : return NT_STATUS_INVALID_LEVEL;
346 5 : case RAW_FILEINFO_NORMALIZED_NAME_INFORMATION:
347 5 : return NT_STATUS_NOT_SUPPORTED;
348 : }
349 :
350 7872 : return NT_STATUS_INVALID_LEVEL;
351 : }
352 :
353 : /*
354 : return info on a pathname
355 : */
356 5291 : NTSTATUS pvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
357 : struct ntvfs_request *req, union smb_fileinfo *info)
358 : {
359 5291 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
360 : struct pvfs_state);
361 0 : struct pvfs_filename *name;
362 0 : NTSTATUS status;
363 :
364 : /* resolve the cifs name to a posix name */
365 5291 : status = pvfs_resolve_name(pvfs, req, info->generic.in.file.path, PVFS_RESOLVE_STREAMS, &name);
366 5291 : if (!NT_STATUS_IS_OK(status)) {
367 77 : return status;
368 : }
369 :
370 5214 : if (!name->stream_exists) {
371 136 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
372 : }
373 :
374 5078 : status = pvfs_can_stat(pvfs, req, name);
375 5078 : if (!NT_STATUS_IS_OK(status)) {
376 32 : return status;
377 : }
378 :
379 5046 : status = pvfs_access_check_simple(pvfs, req, name,
380 : pvfs_fileinfo_access(info));
381 5046 : if (!NT_STATUS_IS_OK(status)) {
382 0 : return status;
383 : }
384 :
385 5046 : status = pvfs_map_fileinfo(pvfs, req, name, info, -1);
386 :
387 5046 : return status;
388 : }
389 :
390 : /*
391 : query info on a open file
392 : */
393 6243 : NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
394 : struct ntvfs_request *req, union smb_fileinfo *info)
395 : {
396 6243 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
397 : struct pvfs_state);
398 0 : struct pvfs_file *f;
399 0 : struct pvfs_file_handle *h;
400 0 : NTSTATUS status;
401 0 : uint32_t access_needed;
402 :
403 6243 : f = pvfs_find_fd(pvfs, req, info->generic.in.file.ntvfs);
404 6243 : if (!f) {
405 0 : return NT_STATUS_INVALID_HANDLE;
406 : }
407 6243 : h = f->handle;
408 :
409 6243 : access_needed = pvfs_fileinfo_access(info);
410 6243 : if ((f->access_mask & access_needed) != access_needed) {
411 1 : return NT_STATUS_ACCESS_DENIED;
412 : }
413 :
414 : /* update the file information */
415 6242 : status = pvfs_resolve_name_handle(pvfs, h);
416 6242 : if (!NT_STATUS_IS_OK(status)) {
417 0 : return status;
418 : }
419 :
420 6242 : status = pvfs_map_fileinfo(pvfs, req, h->name, info, h->fd);
421 :
422 : /* a qfileinfo can fill in a bit more info than a qpathinfo -
423 : now modify the levels that need to be fixed up */
424 6242 : switch (info->generic.level) {
425 172 : case RAW_FILEINFO_STANDARD_INFO:
426 : case RAW_FILEINFO_STANDARD_INFORMATION:
427 172 : if (pvfs_delete_on_close_set(pvfs, h)) {
428 28 : info->standard_info.out.delete_pending = 1;
429 28 : info->standard_info.out.nlink--;
430 : }
431 172 : break;
432 :
433 283 : case RAW_FILEINFO_ALL_INFO:
434 : case RAW_FILEINFO_ALL_INFORMATION:
435 283 : if (pvfs_delete_on_close_set(pvfs, h)) {
436 35 : info->all_info.out.delete_pending = 1;
437 35 : info->all_info.out.nlink--;
438 : }
439 283 : break;
440 :
441 21 : case RAW_FILEINFO_POSITION_INFORMATION:
442 21 : info->position_information.out.position = h->position;
443 21 : break;
444 :
445 71 : case RAW_FILEINFO_ACCESS_INFORMATION:
446 71 : info->access_information.out.access_flags = f->access_mask;
447 71 : break;
448 :
449 13 : case RAW_FILEINFO_MODE_INFORMATION:
450 13 : info->mode_information.out.mode = h->mode;
451 13 : break;
452 :
453 618 : case RAW_FILEINFO_SMB2_ALL_INFORMATION:
454 618 : if (pvfs_delete_on_close_set(pvfs, h)) {
455 2 : info->all_info2.out.delete_pending = 1;
456 2 : info->all_info2.out.nlink--;
457 : }
458 618 : info->all_info2.out.position = h->position;
459 618 : info->all_info2.out.access_mask = f->access_mask;
460 618 : info->all_info2.out.mode = h->mode;
461 618 : break;
462 :
463 5064 : default:
464 5064 : break;
465 : }
466 :
467 6242 : return status;
468 : }
|