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