s4: torture: Add an async SMB2_OP_FLUSH + SMB2_OP_CLOSE test to smb2.compound_async.
[Samba.git] / source3 / smbd / smb2_trans2.c
blob69f6184bff1cf0d701dfb5e809ca5b7ce62e33ee
1 /*
2 Unix SMB/CIFS implementation.
3 SMB transaction2 handling
4 Copyright (C) Jeremy Allison 1994-2007
5 Copyright (C) Stefan (metze) Metzmacher 2003
6 Copyright (C) Volker Lendecke 2005-2007
7 Copyright (C) Steve French 2005
8 Copyright (C) James Peach 2006-2007
10 Extensively modified by Andrew Tridgell, 1995
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "includes.h"
27 #include "ntioctl.h"
28 #include "system/filesys.h"
29 #include "lib/util/time_basic.h"
30 #include "version.h"
31 #include "smbd/smbd.h"
32 #include "smbd/globals.h"
33 #include "../libcli/auth/libcli_auth.h"
34 #include "../librpc/gen_ndr/xattr.h"
35 #include "../librpc/gen_ndr/ndr_security.h"
36 #include "libcli/security/security.h"
37 #include "trans2.h"
38 #include "auth.h"
39 #include "smbprofile.h"
40 #include "rpc_server/srv_pipe_hnd.h"
41 #include "printing.h"
42 #include "lib/util_ea.h"
43 #include "lib/readdir_attr.h"
44 #include "messages.h"
45 #include "libcli/smb/smb2_posix.h"
46 #include "lib/util/string_wrappers.h"
47 #include "source3/lib/substitute.h"
48 #include "source3/lib/adouble.h"
50 #define DIR_ENTRY_SAFETY_MARGIN 4096
52 static char *store_file_unix_basic(connection_struct *conn,
53 char *pdata,
54 files_struct *fsp,
55 const SMB_STRUCT_STAT *psbuf);
57 static char *store_file_unix_basic_info2(connection_struct *conn,
58 char *pdata,
59 files_struct *fsp,
60 const SMB_STRUCT_STAT *psbuf);
62 static uint32_t generate_volume_serial_number(
63 const struct loadparm_substitution *lp_sub,
64 int snum);
66 /****************************************************************************
67 Check if an open file handle is a symlink.
68 ****************************************************************************/
70 NTSTATUS refuse_symlink_fsp(const files_struct *fsp)
73 if (!VALID_STAT(fsp->fsp_name->st)) {
74 return NT_STATUS_ACCESS_DENIED;
76 if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
77 return NT_STATUS_ACCESS_DENIED;
79 if (fsp_get_pathref_fd(fsp) == -1) {
80 return NT_STATUS_ACCESS_DENIED;
82 return NT_STATUS_OK;
85 NTSTATUS check_access_fsp(struct files_struct *fsp,
86 uint32_t access_mask)
88 if (!fsp->fsp_flags.is_fsa) {
89 return smbd_check_access_rights_fsp(fsp->conn->cwd_fsp,
90 fsp,
91 false,
92 access_mask);
94 if (!(fsp->access_mask & access_mask)) {
95 return NT_STATUS_ACCESS_DENIED;
97 return NT_STATUS_OK;
100 #if defined(HAVE_POSIX_ACLS)
101 /****************************************************************************
102 Utility function to open a fsp for a POSIX handle operation.
103 ****************************************************************************/
105 static NTSTATUS get_posix_fsp(connection_struct *conn,
106 struct smb_request *req,
107 struct smb_filename *smb_fname,
108 uint32_t access_mask,
109 files_struct **ret_fsp)
111 NTSTATUS status;
112 uint32_t create_disposition = FILE_OPEN;
113 uint32_t share_access = FILE_SHARE_READ|
114 FILE_SHARE_WRITE|
115 FILE_SHARE_DELETE;
116 struct smb2_create_blobs *posx = NULL;
119 * Only FILE_FLAG_POSIX_SEMANTICS matters on existing files,
120 * but set reasonable defaults.
122 uint32_t file_attributes = 0664;
123 uint32_t oplock = NO_OPLOCK;
124 uint32_t create_options = FILE_NON_DIRECTORY_FILE;
126 /* File or directory must exist. */
127 if (!VALID_STAT(smb_fname->st)) {
128 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
130 /* Cannot be a symlink. */
131 if (S_ISLNK(smb_fname->st.st_ex_mode)) {
132 return NT_STATUS_ACCESS_DENIED;
134 /* Set options correctly for directory open. */
135 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
137 * Only FILE_FLAG_POSIX_SEMANTICS matters on existing
138 * directories, but set reasonable defaults.
140 file_attributes = 0775;
141 create_options = FILE_DIRECTORY_FILE;
144 status = make_smb2_posix_create_ctx(
145 talloc_tos(), &posx, file_attributes);
146 if (!NT_STATUS_IS_OK(status)) {
147 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
148 nt_errstr(status));
149 goto done;
152 status = SMB_VFS_CREATE_FILE(
153 conn, /* conn */
154 req, /* req */
155 NULL, /* dirfsp */
156 smb_fname, /* fname */
157 access_mask, /* access_mask */
158 share_access, /* share_access */
159 create_disposition,/* create_disposition*/
160 create_options, /* create_options */
161 file_attributes,/* file_attributes */
162 oplock, /* oplock_request */
163 NULL, /* lease */
164 0, /* allocation_size */
165 0, /* private_flags */
166 NULL, /* sd */
167 NULL, /* ea_list */
168 ret_fsp, /* result */
169 NULL, /* pinfo */
170 posx, /* in_context */
171 NULL); /* out_context */
173 done:
174 TALLOC_FREE(posx);
175 return status;
177 #endif
179 /********************************************************************
180 Roundup a value to the nearest allocation roundup size boundary.
181 Only do this for Windows clients.
182 ********************************************************************/
184 uint64_t smb_roundup(connection_struct *conn, uint64_t val)
186 uint64_t rval = lp_allocation_roundup_size(SNUM(conn));
188 /* Only roundup for Windows clients. */
189 enum remote_arch_types ra_type = get_remote_arch();
190 if (rval && (ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
191 val = SMB_ROUNDUP(val,rval);
193 return val;
196 /****************************************************************************
197 Utility functions for dealing with extended attributes.
198 ****************************************************************************/
200 /****************************************************************************
201 Refuse to allow clients to overwrite our private xattrs.
202 ****************************************************************************/
204 bool samba_private_attr_name(const char *unix_ea_name)
206 static const char * const prohibited_ea_names[] = {
207 SAMBA_POSIX_INHERITANCE_EA_NAME,
208 SAMBA_XATTR_DOS_ATTRIB,
209 SAMBA_XATTR_MARKER,
210 XATTR_NTACL_NAME,
211 AFPINFO_EA_NETATALK,
212 NULL
215 int i;
217 for (i = 0; prohibited_ea_names[i]; i++) {
218 if (strequal( prohibited_ea_names[i], unix_ea_name))
219 return true;
221 if (strncasecmp_m(unix_ea_name, SAMBA_XATTR_DOSSTREAM_PREFIX,
222 strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) == 0) {
223 return true;
225 return false;
228 /****************************************************************************
229 Get one EA value. Fill in a struct ea_struct.
230 ****************************************************************************/
232 NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx,
233 files_struct *fsp,
234 const char *ea_name,
235 struct ea_struct *pea)
237 /* Get the value of this xattr. Max size is 64k. */
238 size_t attr_size = 256;
239 char *val = NULL;
240 ssize_t sizeret;
241 size_t max_xattr_size = 0;
243 if (fsp == NULL) {
244 return NT_STATUS_INVALID_HANDLE;
247 max_xattr_size = lp_smbd_max_xattr_size(SNUM(fsp->conn));
249 again:
251 val = talloc_realloc(mem_ctx, val, char, attr_size);
252 if (!val) {
253 return NT_STATUS_NO_MEMORY;
256 sizeret = SMB_VFS_FGETXATTR(fsp, ea_name, val, attr_size);
257 if (sizeret == -1 && errno == ERANGE && attr_size < max_xattr_size) {
258 attr_size = max_xattr_size;
259 goto again;
262 if (sizeret == -1) {
263 return map_nt_error_from_unix(errno);
266 DEBUG(10,("get_ea_value: EA %s is of length %u\n", ea_name, (unsigned int)sizeret));
267 dump_data(10, (uint8_t *)val, sizeret);
269 pea->flags = 0;
270 if (strnequal(ea_name, "user.", 5)) {
271 pea->name = talloc_strdup(mem_ctx, &ea_name[5]);
272 } else {
273 pea->name = talloc_strdup(mem_ctx, ea_name);
275 if (pea->name == NULL) {
276 TALLOC_FREE(val);
277 return NT_STATUS_NO_MEMORY;
279 pea->value.data = (unsigned char *)val;
280 pea->value.length = (size_t)sizeret;
281 return NT_STATUS_OK;
284 NTSTATUS get_ea_names_from_fsp(TALLOC_CTX *mem_ctx,
285 files_struct *fsp,
286 char ***pnames,
287 size_t *pnum_names)
289 char smallbuf[1024];
290 /* Get a list of all xattrs. Max namesize is 64k. */
291 size_t ea_namelist_size = 1024;
292 char *ea_namelist = smallbuf;
293 char *to_free = NULL;
295 char *p;
296 char **names;
297 size_t num_names;
298 ssize_t sizeret = -1;
299 NTSTATUS status;
301 if (pnames) {
302 *pnames = NULL;
304 *pnum_names = 0;
306 if (fsp == NULL) {
308 * Callers may pass fsp == NULL when passing smb_fname->fsp of a
309 * symlink. This is ok, handle it here, by just return no EA's
310 * on a symlink.
312 return NT_STATUS_OK;
315 /* should be the case that fsp != NULL */
316 SMB_ASSERT(fsp != NULL);
318 sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
319 ea_namelist_size);
321 if ((sizeret == -1) && (errno == ERANGE)) {
322 ea_namelist_size = 65536;
323 ea_namelist = talloc_array(mem_ctx, char, ea_namelist_size);
324 if (ea_namelist == NULL) {
325 return NT_STATUS_NO_MEMORY;
327 to_free = ea_namelist;
329 sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
330 ea_namelist_size);
333 if (sizeret == -1) {
334 status = map_nt_error_from_unix(errno);
335 TALLOC_FREE(to_free);
336 return status;
339 DBG_DEBUG("ea_namelist size = %zd\n", sizeret);
341 if (sizeret == 0) {
342 TALLOC_FREE(to_free);
343 return NT_STATUS_OK;
347 * Ensure the result is 0-terminated
350 if (ea_namelist[sizeret-1] != '\0') {
351 TALLOC_FREE(to_free);
352 return NT_STATUS_INTERNAL_ERROR;
356 * count the names
358 num_names = 0;
360 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
361 num_names += 1;
364 *pnum_names = num_names;
366 if (pnames == NULL) {
367 TALLOC_FREE(to_free);
368 return NT_STATUS_OK;
371 names = talloc_array(mem_ctx, char *, num_names);
372 if (names == NULL) {
373 DEBUG(0, ("talloc failed\n"));
374 TALLOC_FREE(to_free);
375 return NT_STATUS_NO_MEMORY;
378 if (ea_namelist == smallbuf) {
379 ea_namelist = talloc_memdup(names, smallbuf, sizeret);
380 if (ea_namelist == NULL) {
381 TALLOC_FREE(names);
382 return NT_STATUS_NO_MEMORY;
384 } else {
385 talloc_steal(names, ea_namelist);
387 ea_namelist = talloc_realloc(names, ea_namelist, char,
388 sizeret);
389 if (ea_namelist == NULL) {
390 TALLOC_FREE(names);
391 return NT_STATUS_NO_MEMORY;
395 num_names = 0;
397 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
398 names[num_names++] = p;
401 *pnames = names;
403 return NT_STATUS_OK;
406 /****************************************************************************
407 Return a linked list of the total EA's. Plus the total size
408 ****************************************************************************/
410 static NTSTATUS get_ea_list_from_fsp(TALLOC_CTX *mem_ctx,
411 files_struct *fsp,
412 size_t *pea_total_len,
413 struct ea_list **ea_list)
415 /* Get a list of all xattrs. Max namesize is 64k. */
416 size_t i, num_names;
417 char **names;
418 struct ea_list *ea_list_head = NULL;
419 bool posix_pathnames = false;
420 NTSTATUS status;
422 *pea_total_len = 0;
423 *ea_list = NULL;
425 /* symlink */
426 if (fsp == NULL) {
427 return NT_STATUS_OK;
430 if (!lp_ea_support(SNUM(fsp->conn))) {
431 return NT_STATUS_OK;
434 if (fsp_is_alternate_stream(fsp)) {
435 return NT_STATUS_INVALID_PARAMETER;
438 posix_pathnames = (fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH);
440 status = get_ea_names_from_fsp(talloc_tos(),
441 fsp,
442 &names,
443 &num_names);
445 if (!NT_STATUS_IS_OK(status)) {
446 return status;
449 if (num_names == 0) {
450 return NT_STATUS_OK;
453 for (i=0; i<num_names; i++) {
454 struct ea_list *listp;
455 fstring dos_ea_name;
458 * POSIX EA names are divided into several namespaces by
459 * means of string prefixes. Usually, the system controls
460 * semantics for each namespace, but the 'user' namespace is
461 * available for arbitrary use, which comes closest to
462 * Windows EA semantics. Hence, we map POSIX EAs from the
463 * 'user' namespace to Windows EAs, and just ignore all the
464 * other namespaces. Also, a few specific names in the 'user'
465 * namespace are used by Samba internally. Filter them out as
466 * well, and only present the EAs that are available for
467 * arbitrary use.
469 if (!strnequal(names[i], "user.", 5)
470 || samba_private_attr_name(names[i]))
471 continue;
474 * Filter out any underlying POSIX EA names
475 * that a Windows client can't handle.
477 if (!posix_pathnames &&
478 is_invalid_windows_ea_name(names[i])) {
479 continue;
482 listp = talloc(mem_ctx, struct ea_list);
483 if (listp == NULL) {
484 return NT_STATUS_NO_MEMORY;
487 status = get_ea_value_fsp(listp,
488 fsp,
489 names[i],
490 &listp->ea);
492 if (!NT_STATUS_IS_OK(status)) {
493 TALLOC_FREE(listp);
494 return status;
497 if (listp->ea.value.length == 0) {
499 * We can never return a zero length EA.
500 * Windows reports the EA's as corrupted.
502 TALLOC_FREE(listp);
503 continue;
504 } else if (listp->ea.value.length > 65536) {
506 * SMB clients may report error with file
507 * if large EA is presented to them.
509 DBG_ERR("EA [%s] on file [%s] exceeds "
510 "maximum permitted EA size of 64KiB: %zu\n.",
511 listp->ea.name, fsp_str_dbg(fsp),
512 listp->ea.value.length);
513 TALLOC_FREE(listp);
514 continue;
517 push_ascii_fstring(dos_ea_name, listp->ea.name);
519 *pea_total_len +=
520 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
522 DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len "
523 "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
524 (unsigned int)listp->ea.value.length));
526 DLIST_ADD_END(ea_list_head, listp);
530 /* Add on 4 for total length. */
531 if (*pea_total_len) {
532 *pea_total_len += 4;
535 DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
536 (unsigned int)*pea_total_len));
538 *ea_list = ea_list_head;
539 return NT_STATUS_OK;
542 /****************************************************************************
543 Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer
544 that was filled.
545 ****************************************************************************/
547 static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
548 connection_struct *conn, struct ea_list *ea_list)
550 unsigned int ret_data_size = 4;
551 char *p = pdata;
553 SMB_ASSERT(total_data_size >= 4);
555 if (!lp_ea_support(SNUM(conn))) {
556 SIVAL(pdata,4,0);
557 return 4;
560 for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
561 size_t dos_namelen;
562 fstring dos_ea_name;
563 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
564 dos_namelen = strlen(dos_ea_name);
565 if (dos_namelen > 255 || dos_namelen == 0) {
566 break;
568 if (ea_list->ea.value.length > 65535) {
569 break;
571 if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
572 break;
575 /* We know we have room. */
576 SCVAL(p,0,ea_list->ea.flags);
577 SCVAL(p,1,dos_namelen);
578 SSVAL(p,2,ea_list->ea.value.length);
579 strlcpy(p+4, dos_ea_name, dos_namelen+1);
580 if (ea_list->ea.value.length > 0) {
581 memcpy(p + 4 + dos_namelen + 1,
582 ea_list->ea.value.data,
583 ea_list->ea.value.length);
586 total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
587 p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
590 ret_data_size = PTR_DIFF(p, pdata);
591 DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
592 SIVAL(pdata,0,ret_data_size);
593 return ret_data_size;
596 static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
597 char *pdata,
598 unsigned int total_data_size,
599 unsigned int *ret_data_size,
600 connection_struct *conn,
601 struct ea_list *ea_list)
603 uint8_t *p = (uint8_t *)pdata;
604 uint8_t *last_start = NULL;
605 bool do_store_data = (pdata != NULL);
607 *ret_data_size = 0;
609 if (!lp_ea_support(SNUM(conn))) {
610 return NT_STATUS_NO_EAS_ON_FILE;
613 for (; ea_list; ea_list = ea_list->next) {
614 size_t dos_namelen;
615 fstring dos_ea_name;
616 size_t this_size;
617 size_t pad = 0;
619 if (last_start != NULL && do_store_data) {
620 SIVAL(last_start, 0, PTR_DIFF(p, last_start));
622 last_start = p;
624 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
625 dos_namelen = strlen(dos_ea_name);
626 if (dos_namelen > 255 || dos_namelen == 0) {
627 return NT_STATUS_INTERNAL_ERROR;
629 if (ea_list->ea.value.length > 65535) {
630 return NT_STATUS_INTERNAL_ERROR;
633 this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length;
635 if (ea_list->next) {
636 pad = (4 - (this_size % 4)) % 4;
637 this_size += pad;
640 if (do_store_data) {
641 if (this_size > total_data_size) {
642 return NT_STATUS_INFO_LENGTH_MISMATCH;
645 /* We know we have room. */
646 SIVAL(p, 0x00, 0); /* next offset */
647 SCVAL(p, 0x04, ea_list->ea.flags);
648 SCVAL(p, 0x05, dos_namelen);
649 SSVAL(p, 0x06, ea_list->ea.value.length);
650 strlcpy((char *)(p+0x08), dos_ea_name, dos_namelen+1);
651 memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
652 if (pad) {
653 memset(p + 0x08 + dos_namelen + 1 + ea_list->ea.value.length,
654 '\0',
655 pad);
657 total_data_size -= this_size;
660 p += this_size;
663 *ret_data_size = PTR_DIFF(p, pdata);
664 DEBUG(10,("fill_ea_chained_buffer: data_size = %u\n", *ret_data_size));
665 return NT_STATUS_OK;
668 unsigned int estimate_ea_size(files_struct *fsp)
670 size_t total_ea_len = 0;
671 TALLOC_CTX *mem_ctx;
672 struct ea_list *ea_list = NULL;
673 NTSTATUS status;
675 /* symlink */
676 if (fsp == NULL) {
677 return 0;
680 if (!lp_ea_support(SNUM(fsp->conn))) {
681 return 0;
684 mem_ctx = talloc_stackframe();
686 /* If this is a stream fsp, then we need to instead find the
687 * estimated ea len from the main file, not the stream
688 * (streams cannot have EAs), but the estimate isn't just 0 in
689 * this case! */
690 fsp = metadata_fsp(fsp);
691 (void)get_ea_list_from_fsp(mem_ctx,
692 fsp,
693 &total_ea_len,
694 &ea_list);
696 if(fsp->conn->sconn->using_smb2) {
697 unsigned int ret_data_size;
699 * We're going to be using fill_ea_chained_buffer() to
700 * marshall EA's - this size is significantly larger
701 * than the SMB1 buffer. Re-calculate the size without
702 * marshalling.
704 status = fill_ea_chained_buffer(mem_ctx,
705 NULL,
707 &ret_data_size,
708 fsp->conn,
709 ea_list);
710 if (!NT_STATUS_IS_OK(status)) {
711 ret_data_size = 0;
713 total_ea_len = ret_data_size;
715 TALLOC_FREE(mem_ctx);
716 return total_ea_len;
719 /****************************************************************************
720 Ensure the EA name is case insensitive by matching any existing EA name.
721 ****************************************************************************/
723 static void canonicalize_ea_name(files_struct *fsp,
724 fstring unix_ea_name)
726 size_t total_ea_len;
727 TALLOC_CTX *mem_ctx = talloc_tos();
728 struct ea_list *ea_list;
729 NTSTATUS status = get_ea_list_from_fsp(mem_ctx,
730 fsp,
731 &total_ea_len,
732 &ea_list);
733 if (!NT_STATUS_IS_OK(status)) {
734 return;
737 for (; ea_list; ea_list = ea_list->next) {
738 if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
739 DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
740 &unix_ea_name[5], ea_list->ea.name));
741 strlcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-5);
742 break;
747 /****************************************************************************
748 Set or delete an extended attribute.
749 ****************************************************************************/
751 NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
752 struct ea_list *ea_list)
754 NTSTATUS status;
755 bool posix_pathnames = false;
757 if (!lp_ea_support(SNUM(conn))) {
758 return NT_STATUS_EAS_NOT_SUPPORTED;
761 if (fsp == NULL) {
762 return NT_STATUS_INVALID_HANDLE;
765 posix_pathnames = (fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH);
767 status = refuse_symlink_fsp(fsp);
768 if (!NT_STATUS_IS_OK(status)) {
769 return status;
772 status = check_access_fsp(fsp, FILE_WRITE_EA);
773 if (!NT_STATUS_IS_OK(status)) {
774 return status;
777 /* Setting EAs on streams isn't supported. */
778 if (fsp_is_alternate_stream(fsp)) {
779 return NT_STATUS_INVALID_PARAMETER;
783 * Filter out invalid Windows EA names - before
784 * we set *any* of them.
787 if (!posix_pathnames && ea_list_has_invalid_name(ea_list)) {
788 return STATUS_INVALID_EA_NAME;
791 for (;ea_list; ea_list = ea_list->next) {
792 int ret;
793 fstring unix_ea_name;
796 * Complementing the forward mapping from POSIX EAs to
797 * Windows EAs in get_ea_list_from_fsp(), here we map in the
798 * opposite direction from Windows EAs to the 'user' namespace
799 * of POSIX EAs. Hence, all POSIX EA names the we set here must
800 * start with a 'user.' prefix.
802 fstrcpy(unix_ea_name, "user.");
803 fstrcat(unix_ea_name, ea_list->ea.name);
805 canonicalize_ea_name(fsp, unix_ea_name);
807 DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
809 if (samba_private_attr_name(unix_ea_name)) {
810 DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
811 return NT_STATUS_ACCESS_DENIED;
814 if (ea_list->ea.value.length == 0) {
815 /* Remove the attribute. */
816 DBG_DEBUG("deleting ea name %s on "
817 "file %s by file descriptor.\n",
818 unix_ea_name, fsp_str_dbg(fsp));
819 ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name);
820 #ifdef ENOATTR
821 /* Removing a non existent attribute always succeeds. */
822 if (ret == -1 && errno == ENOATTR) {
823 DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",
824 unix_ea_name));
825 ret = 0;
827 #endif
828 } else {
829 DEBUG(10,("set_ea: setting ea name %s on file "
830 "%s by file descriptor.\n",
831 unix_ea_name, fsp_str_dbg(fsp)));
832 ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name,
833 ea_list->ea.value.data, ea_list->ea.value.length, 0);
836 if (ret == -1) {
837 #ifdef ENOTSUP
838 if (errno == ENOTSUP) {
839 return NT_STATUS_EAS_NOT_SUPPORTED;
841 #endif
842 return map_nt_error_from_unix(errno);
846 return NT_STATUS_OK;
849 /****************************************************************************
850 Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
851 ****************************************************************************/
853 struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
855 struct ea_list *ea_list_head = NULL;
856 size_t offset = 0;
857 size_t bytes_used = 0;
859 while (offset < data_size) {
860 struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);
862 if (!eal) {
863 return NULL;
866 DLIST_ADD_END(ea_list_head, eal);
867 offset += bytes_used;
870 return ea_list_head;
873 /****************************************************************************
874 Count the total EA size needed.
875 ****************************************************************************/
877 static size_t ea_list_size(struct ea_list *ealist)
879 fstring dos_ea_name;
880 struct ea_list *listp;
881 size_t ret = 0;
883 for (listp = ealist; listp; listp = listp->next) {
884 push_ascii_fstring(dos_ea_name, listp->ea.name);
885 ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
887 /* Add on 4 for total length. */
888 if (ret) {
889 ret += 4;
892 return ret;
895 /****************************************************************************
896 Return a union of EA's from a file list and a list of names.
897 The TALLOC context for the two lists *MUST* be identical as we steal
898 memory from one list to add to another. JRA.
899 ****************************************************************************/
901 static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *file_list, size_t *total_ea_len)
903 struct ea_list *nlistp, *flistp;
905 for (nlistp = name_list; nlistp; nlistp = nlistp->next) {
906 for (flistp = file_list; flistp; flistp = flistp->next) {
907 if (strequal(nlistp->ea.name, flistp->ea.name)) {
908 break;
912 if (flistp) {
913 /* Copy the data from this entry. */
914 nlistp->ea.flags = flistp->ea.flags;
915 nlistp->ea.value = flistp->ea.value;
916 } else {
917 /* Null entry. */
918 nlistp->ea.flags = 0;
919 ZERO_STRUCT(nlistp->ea.value);
923 *total_ea_len = ea_list_size(name_list);
924 return name_list;
927 /*********************************************************
928 Routine to check if a given string matches exactly.
929 as a special case a mask of "." does NOT match. That
930 is required for correct wildcard semantics
931 Case can be significant or not.
932 **********************************************************/
934 static bool exact_match(bool has_wild,
935 bool case_sensitive,
936 const char *str,
937 const char *mask)
939 if (mask[0] == '.' && mask[1] == 0) {
940 return false;
943 if (has_wild) {
944 return false;
947 if (case_sensitive) {
948 return strcmp(str,mask)==0;
949 } else {
950 return strcasecmp_m(str,mask) == 0;
954 /****************************************************************************
955 Return the filetype for UNIX extensions.
956 ****************************************************************************/
958 static uint32_t unix_filetype(mode_t mode)
960 if(S_ISREG(mode))
961 return UNIX_TYPE_FILE;
962 else if(S_ISDIR(mode))
963 return UNIX_TYPE_DIR;
964 #ifdef S_ISLNK
965 else if(S_ISLNK(mode))
966 return UNIX_TYPE_SYMLINK;
967 #endif
968 #ifdef S_ISCHR
969 else if(S_ISCHR(mode))
970 return UNIX_TYPE_CHARDEV;
971 #endif
972 #ifdef S_ISBLK
973 else if(S_ISBLK(mode))
974 return UNIX_TYPE_BLKDEV;
975 #endif
976 #ifdef S_ISFIFO
977 else if(S_ISFIFO(mode))
978 return UNIX_TYPE_FIFO;
979 #endif
980 #ifdef S_ISSOCK
981 else if(S_ISSOCK(mode))
982 return UNIX_TYPE_SOCKET;
983 #endif
985 DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode));
986 return UNIX_TYPE_UNKNOWN;
989 /****************************************************************************
990 Map wire perms onto standard UNIX permissions. Obey share restrictions.
991 ****************************************************************************/
993 NTSTATUS unix_perms_from_wire(connection_struct *conn,
994 const SMB_STRUCT_STAT *psbuf,
995 uint32_t perms,
996 enum perm_type ptype,
997 mode_t *ret_perms)
999 mode_t ret = 0;
1001 if (perms == SMB_MODE_NO_CHANGE) {
1002 if (!VALID_STAT(*psbuf)) {
1003 return NT_STATUS_INVALID_PARAMETER;
1004 } else {
1005 *ret_perms = psbuf->st_ex_mode;
1006 return NT_STATUS_OK;
1010 ret = wire_perms_to_unix(perms);
1012 if (ptype == PERM_NEW_FILE) {
1014 * "create mask"/"force create mode" are
1015 * only applied to new files, not existing ones.
1017 ret &= lp_create_mask(SNUM(conn));
1018 /* Add in force bits */
1019 ret |= lp_force_create_mode(SNUM(conn));
1020 } else if (ptype == PERM_NEW_DIR) {
1022 * "directory mask"/"force directory mode" are
1023 * only applied to new directories, not existing ones.
1025 ret &= lp_directory_mask(SNUM(conn));
1026 /* Add in force bits */
1027 ret |= lp_force_directory_mode(SNUM(conn));
1030 *ret_perms = ret;
1031 return NT_STATUS_OK;
1034 /****************************************************************************
1035 Needed to show the msdfs symlinks as directories. Modifies psbuf
1036 to be a directory if it's a msdfs link.
1037 ****************************************************************************/
1039 static bool check_msdfs_link(struct files_struct *dirfsp,
1040 struct smb_filename *atname,
1041 struct smb_filename *smb_fname)
1043 int saved_errno = errno;
1044 if(lp_host_msdfs() &&
1045 lp_msdfs_root(SNUM(dirfsp->conn)) &&
1046 is_msdfs_link(dirfsp, atname)) {
1049 * Copy the returned stat struct from the relative
1050 * to the full pathname.
1052 smb_fname->st = atname->st;
1054 DEBUG(5,("check_msdfs_link: Masquerading msdfs link %s "
1055 "as a directory\n",
1056 smb_fname->base_name));
1057 smb_fname->st.st_ex_mode =
1058 (smb_fname->st.st_ex_mode & 0xFFF) | S_IFDIR;
1059 errno = saved_errno;
1060 return true;
1062 errno = saved_errno;
1063 return false;
1067 /****************************************************************************
1068 Get a level dependent lanman2 dir entry.
1069 ****************************************************************************/
1071 struct smbd_dirptr_lanman2_state {
1072 connection_struct *conn;
1073 uint32_t info_level;
1074 bool check_mangled_names;
1075 bool has_wild;
1076 bool got_exact_match;
1077 bool case_sensitive;
1080 static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx,
1081 void *private_data,
1082 const char *dname,
1083 const char *mask,
1084 char **_fname)
1086 struct smbd_dirptr_lanman2_state *state =
1087 (struct smbd_dirptr_lanman2_state *)private_data;
1088 bool ok;
1089 char mangled_name[13]; /* mangled 8.3 name. */
1090 bool got_match;
1091 const char *fname;
1093 /* Mangle fname if it's an illegal name. */
1094 if (mangle_must_mangle(dname, state->conn->params)) {
1096 * Slow path - ensure we can push the original name as UCS2. If
1097 * not, then just don't return this name.
1099 NTSTATUS status;
1100 size_t ret_len = 0;
1101 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1102 uint8_t *tmp = talloc_array(talloc_tos(),
1103 uint8_t,
1104 len);
1106 status = srvstr_push(NULL,
1107 FLAGS2_UNICODE_STRINGS,
1108 tmp,
1109 dname,
1110 len,
1111 STR_TERMINATE,
1112 &ret_len);
1114 TALLOC_FREE(tmp);
1116 if (!NT_STATUS_IS_OK(status)) {
1117 return false;
1120 ok = name_to_8_3(dname, mangled_name,
1121 true, state->conn->params);
1122 if (!ok) {
1123 return false;
1125 fname = mangled_name;
1126 } else {
1127 fname = dname;
1130 got_match = exact_match(state->has_wild,
1131 state->case_sensitive,
1132 fname, mask);
1133 state->got_exact_match = got_match;
1134 if (!got_match) {
1135 got_match = mask_match(fname, mask,
1136 state->case_sensitive);
1139 if(!got_match && state->check_mangled_names &&
1140 !mangle_is_8_3(fname, false, state->conn->params)) {
1142 * It turns out that NT matches wildcards against
1143 * both long *and* short names. This may explain some
1144 * of the wildcard wierdness from old DOS clients
1145 * that some people have been seeing.... JRA.
1147 /* Force the mangling into 8.3. */
1148 ok = name_to_8_3(fname, mangled_name,
1149 false, state->conn->params);
1150 if (!ok) {
1151 return false;
1154 got_match = exact_match(state->has_wild,
1155 state->case_sensitive,
1156 mangled_name, mask);
1157 state->got_exact_match = got_match;
1158 if (!got_match) {
1159 got_match = mask_match(mangled_name, mask,
1160 state->case_sensitive);
1164 if (!got_match) {
1165 return false;
1168 *_fname = talloc_strdup(ctx, fname);
1169 if (*_fname == NULL) {
1170 return false;
1173 return true;
1176 static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
1177 void *private_data,
1178 struct files_struct *dirfsp,
1179 struct smb_filename *atname,
1180 struct smb_filename *smb_fname,
1181 bool get_dosmode,
1182 uint32_t *_mode)
1184 struct smbd_dirptr_lanman2_state *state =
1185 (struct smbd_dirptr_lanman2_state *)private_data;
1186 bool ms_dfs_link = false;
1188 if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
1189 if (SMB_VFS_LSTAT(state->conn, smb_fname) != 0) {
1190 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1191 "Couldn't lstat [%s] (%s)\n",
1192 smb_fname_str_dbg(smb_fname),
1193 strerror(errno)));
1194 return false;
1196 return true;
1199 if (!VALID_STAT(smb_fname->st) &&
1200 SMB_VFS_STAT(state->conn, smb_fname) != 0) {
1201 /* Needed to show the msdfs symlinks as
1202 * directories */
1204 ms_dfs_link = check_msdfs_link(dirfsp,
1205 atname,
1206 smb_fname);
1207 if (!ms_dfs_link) {
1208 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1209 "Couldn't stat [%s] (%s)\n",
1210 smb_fname_str_dbg(smb_fname),
1211 strerror(errno)));
1212 return false;
1215 *_mode = dos_mode_msdfs(state->conn, smb_fname);
1216 return true;
1219 if (!get_dosmode) {
1220 return true;
1223 *_mode = fdos_mode(smb_fname->fsp);
1224 smb_fname->st = smb_fname->fsp->fsp_name->st;
1226 return true;
1229 static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
1230 connection_struct *conn,
1231 uint16_t flags2,
1232 uint32_t info_level,
1233 struct ea_list *name_list,
1234 bool check_mangled_names,
1235 bool requires_resume_key,
1236 uint32_t mode,
1237 const char *fname,
1238 const struct smb_filename *smb_fname,
1239 int space_remaining,
1240 uint8_t align,
1241 bool do_pad,
1242 char *base_data,
1243 char **ppdata,
1244 char *end_data,
1245 uint64_t *last_entry_off)
1247 char *p, *q, *pdata = *ppdata;
1248 uint32_t reskey=0;
1249 uint64_t file_size = 0;
1250 uint64_t allocation_size = 0;
1251 uint64_t file_id = 0;
1252 size_t len = 0;
1253 struct timespec mdate_ts = {0};
1254 struct timespec adate_ts = {0};
1255 struct timespec cdate_ts = {0};
1256 struct timespec create_date_ts = {0};
1257 time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
1258 char *nameptr;
1259 char *last_entry_ptr;
1260 bool was_8_3;
1261 int off;
1262 int pad = 0;
1263 NTSTATUS status;
1264 struct readdir_attr_data *readdir_attr_data = NULL;
1266 if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) {
1267 file_size = get_file_size_stat(&smb_fname->st);
1269 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
1272 * Skip SMB_VFS_FREADDIR_ATTR if the directory entry is a symlink or
1273 * a DFS symlink.
1275 if (smb_fname->fsp != NULL &&
1276 !(mode & FILE_ATTRIBUTE_REPARSE_POINT)) {
1277 status = SMB_VFS_FREADDIR_ATTR(smb_fname->fsp,
1278 ctx,
1279 &readdir_attr_data);
1280 if (!NT_STATUS_IS_OK(status)) {
1281 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_SUPPORTED,
1282 status)) {
1283 return status;
1288 file_id = SMB_VFS_FS_FILE_ID(conn, &smb_fname->st);
1290 mdate_ts = smb_fname->st.st_ex_mtime;
1291 adate_ts = smb_fname->st.st_ex_atime;
1292 create_date_ts = get_create_timespec(conn, NULL, smb_fname);
1293 cdate_ts = get_change_timespec(conn, NULL, smb_fname);
1295 if (lp_dos_filetime_resolution(SNUM(conn))) {
1296 dos_filetime_timespec(&create_date_ts);
1297 dos_filetime_timespec(&mdate_ts);
1298 dos_filetime_timespec(&adate_ts);
1299 dos_filetime_timespec(&cdate_ts);
1302 create_date = convert_timespec_to_time_t(create_date_ts);
1303 mdate = convert_timespec_to_time_t(mdate_ts);
1304 adate = convert_timespec_to_time_t(adate_ts);
1306 /* align the record */
1307 SMB_ASSERT(align >= 1);
1309 off = (int)PTR_DIFF(pdata, base_data);
1310 pad = (off + (align-1)) & ~(align-1);
1311 pad -= off;
1313 if (pad && pad > space_remaining) {
1314 DEBUG(9,("smbd_marshall_dir_entry: out of space "
1315 "for padding (wanted %u, had %d)\n",
1316 (unsigned int)pad,
1317 space_remaining ));
1318 return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
1321 off += pad;
1322 /* initialize padding to 0 */
1323 if (pad) {
1324 memset(pdata, 0, pad);
1326 space_remaining -= pad;
1328 DEBUG(10,("smbd_marshall_dir_entry: space_remaining = %d\n",
1329 space_remaining ));
1331 pdata += pad;
1332 p = pdata;
1333 last_entry_ptr = p;
1335 pad = 0;
1336 off = 0;
1338 switch (info_level) {
1339 case SMB_FIND_INFO_STANDARD:
1340 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_INFO_STANDARD\n"));
1341 if(requires_resume_key) {
1342 SIVAL(p,0,reskey);
1343 p += 4;
1345 srv_put_dos_date2(p,0,create_date);
1346 srv_put_dos_date2(p,4,adate);
1347 srv_put_dos_date2(p,8,mdate);
1348 SIVAL(p,12,(uint32_t)file_size);
1349 SIVAL(p,16,(uint32_t)allocation_size);
1350 SSVAL(p,20,mode);
1351 p += 23;
1352 nameptr = p;
1353 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1354 p += ucs2_align(base_data, p, 0);
1356 status = srvstr_push(base_data, flags2, p,
1357 fname, PTR_DIFF(end_data, p),
1358 STR_TERMINATE, &len);
1359 if (!NT_STATUS_IS_OK(status)) {
1360 return status;
1362 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1363 if (len > 2) {
1364 SCVAL(nameptr, -1, len - 2);
1365 } else {
1366 SCVAL(nameptr, -1, 0);
1368 } else {
1369 if (len > 1) {
1370 SCVAL(nameptr, -1, len - 1);
1371 } else {
1372 SCVAL(nameptr, -1, 0);
1375 p += len;
1376 break;
1378 case SMB_FIND_EA_SIZE:
1379 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_SIZE\n"));
1380 if (requires_resume_key) {
1381 SIVAL(p,0,reskey);
1382 p += 4;
1384 srv_put_dos_date2(p,0,create_date);
1385 srv_put_dos_date2(p,4,adate);
1386 srv_put_dos_date2(p,8,mdate);
1387 SIVAL(p,12,(uint32_t)file_size);
1388 SIVAL(p,16,(uint32_t)allocation_size);
1389 SSVAL(p,20,mode);
1391 unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1392 SIVAL(p,22,ea_size); /* Extended attributes */
1394 p += 27;
1395 nameptr = p - 1;
1396 status = srvstr_push(base_data, flags2,
1397 p, fname, PTR_DIFF(end_data, p),
1398 STR_TERMINATE | STR_NOALIGN, &len);
1399 if (!NT_STATUS_IS_OK(status)) {
1400 return status;
1402 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1403 if (len > 2) {
1404 len -= 2;
1405 } else {
1406 len = 0;
1408 } else {
1409 if (len > 1) {
1410 len -= 1;
1411 } else {
1412 len = 0;
1415 SCVAL(nameptr,0,len);
1416 p += len;
1417 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1418 break;
1420 case SMB_FIND_EA_LIST:
1422 struct ea_list *file_list = NULL;
1423 size_t ea_len = 0;
1425 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_LIST\n"));
1426 if (!name_list) {
1427 return NT_STATUS_INVALID_PARAMETER;
1429 if (requires_resume_key) {
1430 SIVAL(p,0,reskey);
1431 p += 4;
1433 srv_put_dos_date2(p,0,create_date);
1434 srv_put_dos_date2(p,4,adate);
1435 srv_put_dos_date2(p,8,mdate);
1436 SIVAL(p,12,(uint32_t)file_size);
1437 SIVAL(p,16,(uint32_t)allocation_size);
1438 SSVAL(p,20,mode);
1439 p += 22; /* p now points to the EA area. */
1441 status = get_ea_list_from_fsp(ctx,
1442 smb_fname->fsp,
1443 &ea_len, &file_list);
1444 if (!NT_STATUS_IS_OK(status)) {
1445 file_list = NULL;
1447 name_list = ea_list_union(name_list, file_list, &ea_len);
1449 /* We need to determine if this entry will fit in the space available. */
1450 /* Max string size is 255 bytes. */
1451 if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
1452 DEBUG(9,("smbd_marshall_dir_entry: out of space "
1453 "(wanted %u, had %d)\n",
1454 (unsigned int)PTR_DIFF(p + 255 + ea_len,pdata),
1455 space_remaining ));
1456 return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
1459 /* Push the ea_data followed by the name. */
1460 p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
1461 nameptr = p;
1462 status = srvstr_push(base_data, flags2,
1463 p + 1, fname, PTR_DIFF(end_data, p+1),
1464 STR_TERMINATE | STR_NOALIGN, &len);
1465 if (!NT_STATUS_IS_OK(status)) {
1466 return status;
1468 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1469 if (len > 2) {
1470 len -= 2;
1471 } else {
1472 len = 0;
1474 } else {
1475 if (len > 1) {
1476 len -= 1;
1477 } else {
1478 len = 0;
1481 SCVAL(nameptr,0,len);
1482 p += len + 1;
1483 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1484 break;
1487 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
1488 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
1489 was_8_3 = mangle_is_8_3(fname, True, conn->params);
1490 p += 4;
1491 SIVAL(p,0,reskey); p += 4;
1492 put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1493 put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1494 put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1495 put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1496 SOFF_T(p,0,file_size); p += 8;
1497 SOFF_T(p,0,allocation_size); p += 8;
1498 SIVAL(p,0,mode); p += 4;
1499 q = p; p += 4; /* q is placeholder for name length. */
1500 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1501 SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1502 } else {
1503 unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1504 SIVAL(p,0,ea_size); /* Extended attributes */
1506 p += 4;
1507 /* Clear the short name buffer. This is
1508 * IMPORTANT as not doing so will trigger
1509 * a Win2k client bug. JRA.
1511 if (!was_8_3 && check_mangled_names) {
1512 char mangled_name[13]; /* mangled 8.3 name. */
1513 if (!name_to_8_3(fname,mangled_name,True,
1514 conn->params)) {
1515 /* Error - mangle failed ! */
1516 memset(mangled_name,'\0',12);
1518 mangled_name[12] = 0;
1519 status = srvstr_push(base_data, flags2,
1520 p+2, mangled_name, 24,
1521 STR_UPPER|STR_UNICODE, &len);
1522 if (!NT_STATUS_IS_OK(status)) {
1523 return status;
1525 if (len < 24) {
1526 memset(p + 2 + len,'\0',24 - len);
1528 SSVAL(p, 0, len);
1529 } else {
1530 memset(p,'\0',26);
1532 p += 2 + 24;
1533 status = srvstr_push(base_data, flags2, p,
1534 fname, PTR_DIFF(end_data, p),
1535 STR_TERMINATE_ASCII, &len);
1536 if (!NT_STATUS_IS_OK(status)) {
1537 return status;
1539 SIVAL(q,0,len);
1540 p += len;
1542 len = PTR_DIFF(p, pdata);
1543 pad = (len + (align-1)) & ~(align-1);
1545 * offset to the next entry, the caller
1546 * will overwrite it for the last entry
1547 * that's why we always include the padding
1549 SIVAL(pdata,0,pad);
1551 * set padding to zero
1553 if (do_pad) {
1554 memset(p, 0, pad - len);
1555 p = pdata + pad;
1556 } else {
1557 p = pdata + len;
1559 break;
1561 case SMB_FIND_FILE_DIRECTORY_INFO:
1562 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
1563 p += 4;
1564 SIVAL(p,0,reskey); p += 4;
1565 put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1566 put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1567 put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1568 put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1569 SOFF_T(p,0,file_size); p += 8;
1570 SOFF_T(p,0,allocation_size); p += 8;
1571 SIVAL(p,0,mode); p += 4;
1572 status = srvstr_push(base_data, flags2,
1573 p + 4, fname, PTR_DIFF(end_data, p+4),
1574 STR_TERMINATE_ASCII, &len);
1575 if (!NT_STATUS_IS_OK(status)) {
1576 return status;
1578 SIVAL(p,0,len);
1579 p += 4 + len;
1581 len = PTR_DIFF(p, pdata);
1582 pad = (len + (align-1)) & ~(align-1);
1584 * offset to the next entry, the caller
1585 * will overwrite it for the last entry
1586 * that's why we always include the padding
1588 SIVAL(pdata,0,pad);
1590 * set padding to zero
1592 if (do_pad) {
1593 memset(p, 0, pad - len);
1594 p = pdata + pad;
1595 } else {
1596 p = pdata + len;
1598 break;
1600 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
1601 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
1602 p += 4;
1603 SIVAL(p,0,reskey); p += 4;
1604 put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1605 put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1606 put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1607 put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1608 SOFF_T(p,0,file_size); p += 8;
1609 SOFF_T(p,0,allocation_size); p += 8;
1610 SIVAL(p,0,mode); p += 4;
1611 q = p; p += 4; /* q is placeholder for name length. */
1612 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1613 SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1614 } else {
1615 unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1616 SIVAL(p,0,ea_size); /* Extended attributes */
1618 p +=4;
1619 status = srvstr_push(base_data, flags2, p,
1620 fname, PTR_DIFF(end_data, p),
1621 STR_TERMINATE_ASCII, &len);
1622 if (!NT_STATUS_IS_OK(status)) {
1623 return status;
1625 SIVAL(q, 0, len);
1626 p += len;
1628 len = PTR_DIFF(p, pdata);
1629 pad = (len + (align-1)) & ~(align-1);
1631 * offset to the next entry, the caller
1632 * will overwrite it for the last entry
1633 * that's why we always include the padding
1635 SIVAL(pdata,0,pad);
1637 * set padding to zero
1639 if (do_pad) {
1640 memset(p, 0, pad - len);
1641 p = pdata + pad;
1642 } else {
1643 p = pdata + len;
1645 break;
1647 case SMB_FIND_FILE_NAMES_INFO:
1648 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
1649 p += 4;
1650 SIVAL(p,0,reskey); p += 4;
1651 p += 4;
1652 /* this must *not* be null terminated or w2k gets in a loop trying to set an
1653 acl on a dir (tridge) */
1654 status = srvstr_push(base_data, flags2, p,
1655 fname, PTR_DIFF(end_data, p),
1656 STR_TERMINATE_ASCII, &len);
1657 if (!NT_STATUS_IS_OK(status)) {
1658 return status;
1660 SIVAL(p, -4, len);
1661 p += len;
1663 len = PTR_DIFF(p, pdata);
1664 pad = (len + (align-1)) & ~(align-1);
1666 * offset to the next entry, the caller
1667 * will overwrite it for the last entry
1668 * that's why we always include the padding
1670 SIVAL(pdata,0,pad);
1672 * set padding to zero
1674 if (do_pad) {
1675 memset(p, 0, pad - len);
1676 p = pdata + pad;
1677 } else {
1678 p = pdata + len;
1680 break;
1682 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
1683 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
1684 p += 4;
1685 SIVAL(p,0,reskey); p += 4;
1686 put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1687 put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1688 put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1689 put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1690 SOFF_T(p,0,file_size); p += 8;
1691 SOFF_T(p,0,allocation_size); p += 8;
1692 SIVAL(p,0,mode); p += 4;
1693 q = p; p += 4; /* q is placeholder for name length. */
1694 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1695 SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1696 } else {
1697 unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1698 SIVAL(p,0,ea_size); /* Extended attributes */
1700 p += 4;
1701 SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
1702 SBVAL(p,0,file_id); p += 8;
1703 status = srvstr_push(base_data, flags2, p,
1704 fname, PTR_DIFF(end_data, p),
1705 STR_TERMINATE_ASCII, &len);
1706 if (!NT_STATUS_IS_OK(status)) {
1707 return status;
1709 SIVAL(q, 0, len);
1710 p += len;
1712 len = PTR_DIFF(p, pdata);
1713 pad = (len + (align-1)) & ~(align-1);
1715 * offset to the next entry, the caller
1716 * will overwrite it for the last entry
1717 * that's why we always include the padding
1719 SIVAL(pdata,0,pad);
1721 * set padding to zero
1723 if (do_pad) {
1724 memset(p, 0, pad - len);
1725 p = pdata + pad;
1726 } else {
1727 p = pdata + len;
1729 break;
1731 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
1732 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
1733 was_8_3 = mangle_is_8_3(fname, True, conn->params);
1734 p += 4;
1735 SIVAL(p,0,reskey); p += 4;
1736 put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1737 put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1738 put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1739 put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1740 SOFF_T(p,0,file_size); p += 8;
1741 SOFF_T(p,0,allocation_size); p += 8;
1742 SIVAL(p,0,mode); p += 4;
1743 q = p; p += 4; /* q is placeholder for name length */
1744 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1745 SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1746 } else if (readdir_attr_data &&
1747 readdir_attr_data->type == RDATTR_AAPL) {
1749 * OS X specific SMB2 extension negotiated via
1750 * AAPL create context: return max_access in
1751 * ea_size field.
1753 SIVAL(p, 0, readdir_attr_data->attr_data.aapl.max_access);
1754 } else {
1755 unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1756 SIVAL(p,0,ea_size); /* Extended attributes */
1758 p += 4;
1760 if (readdir_attr_data &&
1761 readdir_attr_data->type == RDATTR_AAPL) {
1763 * OS X specific SMB2 extension negotiated via
1764 * AAPL create context: return resource fork
1765 * length and compressed FinderInfo in
1766 * shortname field.
1768 * According to documentation short_name_len
1769 * should be 0, but on the wire behaviour
1770 * shows its set to 24 by clients.
1772 SSVAL(p, 0, 24);
1774 /* Resourefork length */
1775 SBVAL(p, 2, readdir_attr_data->attr_data.aapl.rfork_size);
1777 /* Compressed FinderInfo */
1778 memcpy(p + 10, &readdir_attr_data->attr_data.aapl.finder_info, 16);
1779 } else if (!was_8_3 && check_mangled_names) {
1780 char mangled_name[13]; /* mangled 8.3 name. */
1781 if (!name_to_8_3(fname,mangled_name,True,
1782 conn->params)) {
1783 /* Error - mangle failed ! */
1784 memset(mangled_name,'\0',12);
1786 mangled_name[12] = 0;
1787 status = srvstr_push(base_data, flags2,
1788 p+2, mangled_name, 24,
1789 STR_UPPER|STR_UNICODE, &len);
1790 if (!NT_STATUS_IS_OK(status)) {
1791 return status;
1793 SSVAL(p, 0, len);
1794 if (len < 24) {
1795 memset(p + 2 + len,'\0',24 - len);
1797 SSVAL(p, 0, len);
1798 } else {
1799 /* Clear the short name buffer. This is
1800 * IMPORTANT as not doing so will trigger
1801 * a Win2k client bug. JRA.
1803 memset(p,'\0',26);
1805 p += 26;
1807 /* Reserved ? */
1808 if (readdir_attr_data &&
1809 readdir_attr_data->type == RDATTR_AAPL) {
1811 * OS X specific SMB2 extension negotiated via
1812 * AAPL create context: return UNIX mode in
1813 * reserved field.
1815 uint16_t aapl_mode = (uint16_t)readdir_attr_data->attr_data.aapl.unix_mode;
1816 SSVAL(p, 0, aapl_mode);
1817 } else {
1818 SSVAL(p, 0, 0);
1820 p += 2;
1822 SBVAL(p,0,file_id); p += 8;
1823 status = srvstr_push(base_data, flags2, p,
1824 fname, PTR_DIFF(end_data, p),
1825 STR_TERMINATE_ASCII, &len);
1826 if (!NT_STATUS_IS_OK(status)) {
1827 return status;
1829 SIVAL(q,0,len);
1830 p += len;
1832 len = PTR_DIFF(p, pdata);
1833 pad = (len + (align-1)) & ~(align-1);
1835 * offset to the next entry, the caller
1836 * will overwrite it for the last entry
1837 * that's why we always include the padding
1839 SIVAL(pdata,0,pad);
1841 * set padding to zero
1843 if (do_pad) {
1844 memset(p, 0, pad - len);
1845 p = pdata + pad;
1846 } else {
1847 p = pdata + len;
1849 break;
1851 /* CIFS UNIX Extension. */
1853 case SMB_FIND_FILE_UNIX:
1854 case SMB_FIND_FILE_UNIX_INFO2:
1855 p+= 4;
1856 SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
1858 /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
1860 if (info_level == SMB_FIND_FILE_UNIX) {
1861 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX\n"));
1862 p = store_file_unix_basic(conn, p,
1863 NULL, &smb_fname->st);
1864 status = srvstr_push(base_data, flags2, p,
1865 fname, PTR_DIFF(end_data, p),
1866 STR_TERMINATE, &len);
1867 if (!NT_STATUS_IS_OK(status)) {
1868 return status;
1870 } else {
1871 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
1872 p = store_file_unix_basic_info2(conn, p,
1873 NULL, &smb_fname->st);
1874 nameptr = p;
1875 p += 4;
1876 status = srvstr_push(base_data, flags2, p, fname,
1877 PTR_DIFF(end_data, p), 0, &len);
1878 if (!NT_STATUS_IS_OK(status)) {
1879 return status;
1881 SIVAL(nameptr, 0, len);
1884 p += len;
1886 len = PTR_DIFF(p, pdata);
1887 pad = (len + (align-1)) & ~(align-1);
1889 * offset to the next entry, the caller
1890 * will overwrite it for the last entry
1891 * that's why we always include the padding
1893 SIVAL(pdata,0,pad);
1895 * set padding to zero
1897 if (do_pad) {
1898 memset(p, 0, pad - len);
1899 p = pdata + pad;
1900 } else {
1901 p = pdata + len;
1903 /* End of SMB_QUERY_FILE_UNIX_BASIC */
1905 break;
1907 default:
1908 return NT_STATUS_INVALID_LEVEL;
1911 if (PTR_DIFF(p,pdata) > space_remaining) {
1912 DEBUG(9,("smbd_marshall_dir_entry: out of space "
1913 "(wanted %u, had %d)\n",
1914 (unsigned int)PTR_DIFF(p,pdata),
1915 space_remaining ));
1916 return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
1919 /* Setup the last entry pointer, as an offset from base_data */
1920 *last_entry_off = PTR_DIFF(last_entry_ptr,base_data);
1921 /* Advance the data pointer to the next slot */
1922 *ppdata = p;
1924 return NT_STATUS_OK;
1927 NTSTATUS smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
1928 connection_struct *conn,
1929 struct dptr_struct *dirptr,
1930 uint16_t flags2,
1931 const char *path_mask,
1932 uint32_t dirtype,
1933 int info_level,
1934 int requires_resume_key,
1935 bool dont_descend,
1936 bool ask_sharemode,
1937 bool get_dosmode,
1938 uint8_t align,
1939 bool do_pad,
1940 char **ppdata,
1941 char *base_data,
1942 char *end_data,
1943 int space_remaining,
1944 struct smb_filename **_smb_fname,
1945 bool *got_exact_match,
1946 int *_last_entry_off,
1947 struct ea_list *name_list,
1948 struct file_id *file_id)
1950 const char *p;
1951 const char *mask = NULL;
1952 long prev_dirpos = 0;
1953 uint32_t mode = 0;
1954 char *fname = NULL;
1955 struct smb_filename *smb_fname = NULL;
1956 struct smbd_dirptr_lanman2_state state;
1957 bool ok;
1958 uint64_t last_entry_off = 0;
1959 NTSTATUS status;
1960 enum mangled_names_options mangled_names;
1961 bool marshall_with_83_names;
1963 mangled_names = lp_mangled_names(conn->params);
1965 ZERO_STRUCT(state);
1966 state.conn = conn;
1967 state.info_level = info_level;
1968 if (mangled_names != MANGLED_NAMES_NO) {
1969 state.check_mangled_names = true;
1971 state.has_wild = dptr_has_wild(dirptr);
1972 state.got_exact_match = false;
1973 state.case_sensitive = dptr_case_sensitive(dirptr);
1975 *got_exact_match = false;
1977 p = strrchr_m(path_mask,'/');
1978 if(p != NULL) {
1979 if(p[1] == '\0') {
1980 mask = "*.*";
1981 } else {
1982 mask = p+1;
1984 } else {
1985 mask = path_mask;
1988 ok = smbd_dirptr_get_entry(ctx,
1989 dirptr,
1990 mask,
1991 dirtype,
1992 dont_descend,
1993 ask_sharemode,
1994 get_dosmode,
1995 smbd_dirptr_lanman2_match_fn,
1996 smbd_dirptr_lanman2_mode_fn,
1997 &state,
1998 &fname,
1999 &smb_fname,
2000 &mode,
2001 &prev_dirpos);
2002 if (!ok) {
2003 return NT_STATUS_END_OF_FILE;
2006 *got_exact_match = state.got_exact_match;
2008 marshall_with_83_names = (mangled_names == MANGLED_NAMES_YES);
2010 status = smbd_marshall_dir_entry(ctx,
2011 conn,
2012 flags2,
2013 info_level,
2014 name_list,
2015 marshall_with_83_names,
2016 requires_resume_key,
2017 mode,
2018 fname,
2019 smb_fname,
2020 space_remaining,
2021 align,
2022 do_pad,
2023 base_data,
2024 ppdata,
2025 end_data,
2026 &last_entry_off);
2027 if (NT_STATUS_EQUAL(status, NT_STATUS_ILLEGAL_CHARACTER)) {
2028 DEBUG(1,("Conversion error: illegal character: %s\n",
2029 smb_fname_str_dbg(smb_fname)));
2032 if (file_id != NULL) {
2033 *file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
2036 if (!NT_STATUS_IS_OK(status) &&
2037 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES))
2039 TALLOC_FREE(smb_fname);
2040 TALLOC_FREE(fname);
2041 return status;
2044 if (_smb_fname != NULL) {
2046 * smb_fname is already talloc'ed off ctx.
2047 * We just need to make sure we don't return
2048 * any stream_name, and replace base_name
2049 * with fname in case base_name got mangled.
2050 * This allows us to preserve any smb_fname->fsp
2051 * for asynchronous handle lookups.
2053 TALLOC_FREE(smb_fname->stream_name);
2054 TALLOC_FREE(smb_fname->base_name);
2055 smb_fname->base_name = talloc_strdup(smb_fname, fname);
2057 if (smb_fname->base_name == NULL) {
2058 TALLOC_FREE(smb_fname);
2059 TALLOC_FREE(fname);
2060 return NT_STATUS_NO_MEMORY;
2062 *_smb_fname = smb_fname;
2063 } else {
2064 TALLOC_FREE(smb_fname);
2066 TALLOC_FREE(fname);
2068 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
2069 dptr_SeekDir(dirptr, prev_dirpos);
2070 return status;
2073 *_last_entry_off = last_entry_off;
2074 return NT_STATUS_OK;
2077 unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
2079 const struct loadparm_substitution *lp_sub =
2080 loadparm_s3_global_substitution();
2082 E_md4hash(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),objid);
2083 return objid;
2086 static void samba_extended_info_version(struct smb_extended_info *extended_info)
2088 SMB_ASSERT(extended_info != NULL);
2090 extended_info->samba_magic = SAMBA_EXTENDED_INFO_MAGIC;
2091 extended_info->samba_version = ((SAMBA_VERSION_MAJOR & 0xff) << 24)
2092 | ((SAMBA_VERSION_MINOR & 0xff) << 16)
2093 | ((SAMBA_VERSION_RELEASE & 0xff) << 8);
2094 #ifdef SAMBA_VERSION_REVISION
2095 extended_info->samba_version |= (tolower(*SAMBA_VERSION_REVISION) - 'a' + 1) & 0xff;
2096 #endif
2097 extended_info->samba_subversion = 0;
2098 #ifdef SAMBA_VERSION_RC_RELEASE
2099 extended_info->samba_subversion |= (SAMBA_VERSION_RC_RELEASE & 0xff) << 24;
2100 #else
2101 #ifdef SAMBA_VERSION_PRE_RELEASE
2102 extended_info->samba_subversion |= (SAMBA_VERSION_PRE_RELEASE & 0xff) << 16;
2103 #endif
2104 #endif
2105 #ifdef SAMBA_VERSION_VENDOR_PATCH
2106 extended_info->samba_subversion |= (SAMBA_VERSION_VENDOR_PATCH & 0xffff);
2107 #endif
2108 extended_info->samba_gitcommitdate = 0;
2109 #ifdef SAMBA_VERSION_COMMIT_TIME
2110 unix_to_nt_time(&extended_info->samba_gitcommitdate, SAMBA_VERSION_COMMIT_TIME);
2111 #endif
2113 memset(extended_info->samba_version_string, 0,
2114 sizeof(extended_info->samba_version_string));
2116 snprintf (extended_info->samba_version_string,
2117 sizeof(extended_info->samba_version_string),
2118 "%s", samba_version_string());
2121 NTSTATUS smbd_do_qfsinfo(struct smbXsrv_connection *xconn,
2122 connection_struct *conn,
2123 TALLOC_CTX *mem_ctx,
2124 uint16_t info_level,
2125 uint16_t flags2,
2126 unsigned int max_data_bytes,
2127 size_t *fixed_portion,
2128 struct smb_filename *fname,
2129 char **ppdata,
2130 int *ret_data_len)
2132 const struct loadparm_substitution *lp_sub =
2133 loadparm_s3_global_substitution();
2134 char *pdata, *end_data;
2135 int data_len = 0;
2136 size_t len = 0;
2137 const char *vname = volume_label(talloc_tos(), SNUM(conn));
2138 int snum = SNUM(conn);
2139 const char *fstype = lp_fstype(SNUM(conn));
2140 const char *filename = NULL;
2141 const uint64_t bytes_per_sector = 512;
2142 uint32_t additional_flags = 0;
2143 struct smb_filename smb_fname;
2144 SMB_STRUCT_STAT st;
2145 NTSTATUS status = NT_STATUS_OK;
2146 uint64_t df_ret;
2147 uint32_t serial;
2149 if (fname == NULL || fname->base_name == NULL) {
2150 filename = ".";
2151 } else {
2152 filename = fname->base_name;
2155 if (IS_IPC(conn)) {
2156 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
2157 DEBUG(0,("smbd_do_qfsinfo: not an allowed "
2158 "info level (0x%x) on IPC$.\n",
2159 (unsigned int)info_level));
2160 return NT_STATUS_ACCESS_DENIED;
2164 DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level));
2166 smb_fname = (struct smb_filename) {
2167 .base_name = discard_const_p(char, filename),
2168 .flags = fname ? fname->flags : 0,
2169 .twrp = fname ? fname->twrp : 0,
2172 if(info_level != SMB_FS_QUOTA_INFORMATION
2173 && SMB_VFS_STAT(conn, &smb_fname) != 0) {
2174 DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
2175 return map_nt_error_from_unix(errno);
2178 st = smb_fname.st;
2180 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
2181 return NT_STATUS_INVALID_PARAMETER;
2184 *ppdata = (char *)SMB_REALLOC(
2185 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2186 if (*ppdata == NULL) {
2187 return NT_STATUS_NO_MEMORY;
2190 pdata = *ppdata;
2191 memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2192 end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2194 *fixed_portion = 0;
2196 switch (info_level) {
2197 case SMB_INFO_ALLOCATION:
2199 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
2200 data_len = 18;
2201 df_ret = get_dfree_info(conn, &smb_fname, &bsize,
2202 &dfree, &dsize);
2203 if (df_ret == (uint64_t)-1) {
2204 return map_nt_error_from_unix(errno);
2207 block_size = lp_block_size(snum);
2208 if (bsize < block_size) {
2209 uint64_t factor = block_size/bsize;
2210 bsize = block_size;
2211 dsize /= factor;
2212 dfree /= factor;
2214 if (bsize > block_size) {
2215 uint64_t factor = bsize/block_size;
2216 bsize = block_size;
2217 dsize *= factor;
2218 dfree *= factor;
2220 sectors_per_unit = bsize/bytes_per_sector;
2222 DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
2223 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
2224 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2227 * For large drives, return max values and not modulo.
2229 dsize = MIN(dsize, UINT32_MAX);
2230 dfree = MIN(dfree, UINT32_MAX);
2232 SIVAL(pdata,l1_idFileSystem,st.st_ex_dev);
2233 SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
2234 SIVAL(pdata,l1_cUnit,dsize);
2235 SIVAL(pdata,l1_cUnitAvail,dfree);
2236 SSVAL(pdata,l1_cbSector,bytes_per_sector);
2237 break;
2240 case SMB_INFO_VOLUME:
2241 /* Return volume name */
2243 * Add volume serial number - hash of a combination of
2244 * the called hostname and the service name.
2246 serial = generate_volume_serial_number(lp_sub, snum);
2247 SIVAL(pdata,0,serial);
2249 * Win2k3 and previous mess this up by sending a name length
2250 * one byte short. I believe only older clients (OS/2 Win9x) use
2251 * this call so try fixing this by adding a terminating null to
2252 * the pushed string. The change here was adding the STR_TERMINATE. JRA.
2254 status = srvstr_push(
2255 pdata, flags2,
2256 pdata+l2_vol_szVolLabel, vname,
2257 PTR_DIFF(end_data, pdata+l2_vol_szVolLabel),
2258 STR_NOALIGN|STR_TERMINATE, &len);
2259 if (!NT_STATUS_IS_OK(status)) {
2260 return status;
2262 SCVAL(pdata,l2_vol_cch,len);
2263 data_len = l2_vol_szVolLabel + len;
2264 DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %u, "
2265 "name = %s serial = 0x%04"PRIx32"\n",
2266 (unsigned)convert_timespec_to_time_t(st.st_ex_ctime),
2267 (unsigned)len, vname, serial));
2268 break;
2270 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2271 case SMB_FS_ATTRIBUTE_INFORMATION:
2273 additional_flags = 0;
2274 #if defined(HAVE_SYS_QUOTAS)
2275 additional_flags |= FILE_VOLUME_QUOTAS;
2276 #endif
2278 if(lp_nt_acl_support(SNUM(conn))) {
2279 additional_flags |= FILE_PERSISTENT_ACLS;
2282 /* Capabilities are filled in at connection time through STATVFS call */
2283 additional_flags |= conn->fs_capabilities;
2284 additional_flags |= lp_parm_int(conn->params->service,
2285 "share", "fake_fscaps",
2288 SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
2289 FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
2290 additional_flags); /* FS ATTRIBUTES */
2292 SIVAL(pdata,4,255); /* Max filename component length */
2293 /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
2294 and will think we can't do long filenames */
2295 status = srvstr_push(pdata, flags2, pdata+12, fstype,
2296 PTR_DIFF(end_data, pdata+12),
2297 STR_UNICODE, &len);
2298 if (!NT_STATUS_IS_OK(status)) {
2299 return status;
2301 SIVAL(pdata,8,len);
2302 data_len = 12 + len;
2303 if (max_data_bytes >= 16 && data_len > max_data_bytes) {
2304 /* the client only requested a portion of the
2305 file system name */
2306 data_len = max_data_bytes;
2307 status = STATUS_BUFFER_OVERFLOW;
2309 *fixed_portion = 16;
2310 break;
2312 case SMB_QUERY_FS_LABEL_INFO:
2313 case SMB_FS_LABEL_INFORMATION:
2314 status = srvstr_push(pdata, flags2, pdata+4, vname,
2315 PTR_DIFF(end_data, pdata+4), 0, &len);
2316 if (!NT_STATUS_IS_OK(status)) {
2317 return status;
2319 data_len = 4 + len;
2320 SIVAL(pdata,0,len);
2321 break;
2323 case SMB_QUERY_FS_VOLUME_INFO:
2324 case SMB_FS_VOLUME_INFORMATION:
2325 put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER,
2326 pdata, &st.st_ex_btime);
2328 * Add volume serial number - hash of a combination of
2329 * the called hostname and the service name.
2331 serial = generate_volume_serial_number(lp_sub, snum);
2332 SIVAL(pdata,8,serial);
2334 /* Max label len is 32 characters. */
2335 status = srvstr_push(pdata, flags2, pdata+18, vname,
2336 PTR_DIFF(end_data, pdata+18),
2337 STR_UNICODE, &len);
2338 if (!NT_STATUS_IS_OK(status)) {
2339 return status;
2341 SIVAL(pdata,12,len);
2342 data_len = 18+len;
2344 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO "
2345 "namelen = %d, vol=%s serv=%s "
2346 "serial=0x%04"PRIx32"\n",
2347 (int)strlen(vname),vname,
2348 lp_servicename(talloc_tos(), lp_sub, snum),
2349 serial));
2350 if (max_data_bytes >= 24 && data_len > max_data_bytes) {
2351 /* the client only requested a portion of the
2352 volume label */
2353 data_len = max_data_bytes;
2354 status = STATUS_BUFFER_OVERFLOW;
2356 *fixed_portion = 24;
2357 break;
2359 case SMB_QUERY_FS_SIZE_INFO:
2360 case SMB_FS_SIZE_INFORMATION:
2362 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
2363 data_len = 24;
2364 df_ret = get_dfree_info(conn, &smb_fname, &bsize,
2365 &dfree, &dsize);
2366 if (df_ret == (uint64_t)-1) {
2367 return map_nt_error_from_unix(errno);
2369 block_size = lp_block_size(snum);
2370 if (bsize < block_size) {
2371 uint64_t factor = block_size/bsize;
2372 bsize = block_size;
2373 dsize /= factor;
2374 dfree /= factor;
2376 if (bsize > block_size) {
2377 uint64_t factor = bsize/block_size;
2378 bsize = block_size;
2379 dsize *= factor;
2380 dfree *= factor;
2382 sectors_per_unit = bsize/bytes_per_sector;
2383 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
2384 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
2385 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2386 SBIG_UINT(pdata,0,dsize);
2387 SBIG_UINT(pdata,8,dfree);
2388 SIVAL(pdata,16,sectors_per_unit);
2389 SIVAL(pdata,20,bytes_per_sector);
2390 *fixed_portion = 24;
2391 break;
2394 case SMB_FS_FULL_SIZE_INFORMATION:
2396 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
2397 data_len = 32;
2398 df_ret = get_dfree_info(conn, &smb_fname, &bsize,
2399 &dfree, &dsize);
2400 if (df_ret == (uint64_t)-1) {
2401 return map_nt_error_from_unix(errno);
2403 block_size = lp_block_size(snum);
2404 if (bsize < block_size) {
2405 uint64_t factor = block_size/bsize;
2406 bsize = block_size;
2407 dsize /= factor;
2408 dfree /= factor;
2410 if (bsize > block_size) {
2411 uint64_t factor = bsize/block_size;
2412 bsize = block_size;
2413 dsize *= factor;
2414 dfree *= factor;
2416 sectors_per_unit = bsize/bytes_per_sector;
2417 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
2418 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
2419 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2420 SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
2421 SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
2422 SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
2423 SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
2424 SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
2425 *fixed_portion = 32;
2426 break;
2429 case SMB_QUERY_FS_DEVICE_INFO:
2430 case SMB_FS_DEVICE_INFORMATION:
2432 uint32_t characteristics = FILE_DEVICE_IS_MOUNTED;
2434 if (!CAN_WRITE(conn)) {
2435 characteristics |= FILE_READ_ONLY_DEVICE;
2437 data_len = 8;
2438 SIVAL(pdata,0,FILE_DEVICE_DISK); /* dev type */
2439 SIVAL(pdata,4,characteristics);
2440 *fixed_portion = 8;
2441 break;
2444 #ifdef HAVE_SYS_QUOTAS
2445 case SMB_FS_QUOTA_INFORMATION:
2447 * what we have to send --metze:
2449 * Unknown1: 24 NULL bytes
2450 * Soft Quota Treshold: 8 bytes seems like uint64_t or so
2451 * Hard Quota Limit: 8 bytes seems like uint64_t or so
2452 * Quota Flags: 2 byte :
2453 * Unknown3: 6 NULL bytes
2455 * 48 bytes total
2457 * details for Quota Flags:
2459 * 0x0020 Log Limit: log if the user exceeds his Hard Quota
2460 * 0x0010 Log Warn: log if the user exceeds his Soft Quota
2461 * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
2462 * 0x0001 Enable Quotas: enable quota for this fs
2466 /* we need to fake up a fsp here,
2467 * because its not send in this call
2469 files_struct fsp;
2470 SMB_NTQUOTA_STRUCT quotas;
2472 ZERO_STRUCT(fsp);
2473 ZERO_STRUCT(quotas);
2475 fsp.conn = conn;
2476 fsp.fnum = FNUM_FIELD_INVALID;
2478 /* access check */
2479 if (get_current_uid(conn) != 0) {
2480 DEBUG(0,("get_user_quota: access_denied "
2481 "service [%s] user [%s]\n",
2482 lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
2483 conn->session_info->unix_info->unix_name));
2484 return NT_STATUS_ACCESS_DENIED;
2487 status = vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE,
2488 NULL, &quotas);
2489 if (!NT_STATUS_IS_OK(status)) {
2490 DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2491 return status;
2494 data_len = 48;
2496 DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",
2497 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2499 /* Unknown1 24 NULL bytes*/
2500 SBIG_UINT(pdata,0,(uint64_t)0);
2501 SBIG_UINT(pdata,8,(uint64_t)0);
2502 SBIG_UINT(pdata,16,(uint64_t)0);
2504 /* Default Soft Quota 8 bytes */
2505 SBIG_UINT(pdata,24,quotas.softlim);
2507 /* Default Hard Quota 8 bytes */
2508 SBIG_UINT(pdata,32,quotas.hardlim);
2510 /* Quota flag 2 bytes */
2511 SSVAL(pdata,40,quotas.qflags);
2513 /* Unknown3 6 NULL bytes */
2514 SSVAL(pdata,42,0);
2515 SIVAL(pdata,44,0);
2517 break;
2519 #endif /* HAVE_SYS_QUOTAS */
2520 case SMB_FS_OBJECTID_INFORMATION:
2522 unsigned char objid[16];
2523 struct smb_extended_info extended_info;
2524 memcpy(pdata,create_volume_objectid(conn, objid),16);
2525 samba_extended_info_version (&extended_info);
2526 SIVAL(pdata,16,extended_info.samba_magic);
2527 SIVAL(pdata,20,extended_info.samba_version);
2528 SIVAL(pdata,24,extended_info.samba_subversion);
2529 SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
2530 memcpy(pdata+36,extended_info.samba_version_string,28);
2531 data_len = 64;
2532 break;
2535 case SMB_FS_SECTOR_SIZE_INFORMATION:
2537 data_len = 28;
2539 * These values match a physical Windows Server 2012
2540 * share backed by NTFS atop spinning rust.
2542 DEBUG(5, ("SMB_FS_SECTOR_SIZE_INFORMATION:"));
2543 /* logical_bytes_per_sector */
2544 SIVAL(pdata, 0, bytes_per_sector);
2545 /* phys_bytes_per_sector_atomic */
2546 SIVAL(pdata, 4, bytes_per_sector);
2547 /* phys_bytes_per_sector_perf */
2548 SIVAL(pdata, 8, bytes_per_sector);
2549 /* fs_effective_phys_bytes_per_sector_atomic */
2550 SIVAL(pdata, 12, bytes_per_sector);
2551 /* flags */
2552 SIVAL(pdata, 16, SSINFO_FLAGS_ALIGNED_DEVICE
2553 | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE);
2554 /* byte_off_sector_align */
2555 SIVAL(pdata, 20, 0);
2556 /* byte_off_partition_align */
2557 SIVAL(pdata, 24, 0);
2558 *fixed_portion = 28;
2559 break;
2563 #if defined(WITH_SMB1SERVER)
2565 * Query the version and capabilities of the CIFS UNIX extensions
2566 * in use.
2569 case SMB_QUERY_CIFS_UNIX_INFO:
2571 bool large_write = lp_min_receive_file_size() &&
2572 !smb1_srv_is_signing_active(xconn);
2573 bool large_read = !smb1_srv_is_signing_active(xconn);
2574 int encrypt_caps = 0;
2576 if (!lp_smb1_unix_extensions()) {
2577 return NT_STATUS_INVALID_LEVEL;
2580 switch (conn->encrypt_level) {
2581 case SMB_SIGNING_OFF:
2582 encrypt_caps = 0;
2583 break;
2584 case SMB_SIGNING_DESIRED:
2585 case SMB_SIGNING_IF_REQUIRED:
2586 case SMB_SIGNING_DEFAULT:
2587 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
2588 break;
2589 case SMB_SIGNING_REQUIRED:
2590 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
2591 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
2592 large_write = false;
2593 large_read = false;
2594 break;
2597 data_len = 12;
2598 SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
2599 SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
2601 /* We have POSIX ACLs, pathname, encryption,
2602 * large read/write, and locking capability. */
2604 SBIG_UINT(pdata,4,((uint64_t)(
2605 CIFS_UNIX_POSIX_ACLS_CAP|
2606 CIFS_UNIX_POSIX_PATHNAMES_CAP|
2607 CIFS_UNIX_FCNTL_LOCKS_CAP|
2608 CIFS_UNIX_EXTATTR_CAP|
2609 CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
2610 encrypt_caps|
2611 (large_read ? CIFS_UNIX_LARGE_READ_CAP : 0) |
2612 (large_write ?
2613 CIFS_UNIX_LARGE_WRITE_CAP : 0))));
2614 break;
2616 #endif
2618 case SMB_QUERY_POSIX_FS_INFO:
2620 int rc;
2621 struct vfs_statvfs_struct svfs;
2623 if (!lp_smb1_unix_extensions()) {
2624 return NT_STATUS_INVALID_LEVEL;
2627 rc = SMB_VFS_STATVFS(conn, &smb_fname, &svfs);
2629 if (!rc) {
2630 data_len = 56;
2631 SIVAL(pdata,0,svfs.OptimalTransferSize);
2632 SIVAL(pdata,4,svfs.BlockSize);
2633 SBIG_UINT(pdata,8,svfs.TotalBlocks);
2634 SBIG_UINT(pdata,16,svfs.BlocksAvail);
2635 SBIG_UINT(pdata,24,svfs.UserBlocksAvail);
2636 SBIG_UINT(pdata,32,svfs.TotalFileNodes);
2637 SBIG_UINT(pdata,40,svfs.FreeFileNodes);
2638 SBIG_UINT(pdata,48,svfs.FsIdentifier);
2639 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
2640 #ifdef EOPNOTSUPP
2641 } else if (rc == EOPNOTSUPP) {
2642 return NT_STATUS_INVALID_LEVEL;
2643 #endif /* EOPNOTSUPP */
2644 } else {
2645 DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2646 return NT_STATUS_DOS(ERRSRV, ERRerror);
2648 break;
2651 case SMB_QUERY_POSIX_WHOAMI:
2653 uint32_t flags = 0;
2654 uint32_t sid_bytes;
2655 uint32_t i;
2657 if (!lp_smb1_unix_extensions()) {
2658 return NT_STATUS_INVALID_LEVEL;
2661 if (max_data_bytes < 40) {
2662 return NT_STATUS_BUFFER_TOO_SMALL;
2665 if (security_session_user_level(conn->session_info, NULL) < SECURITY_USER) {
2666 flags |= SMB_WHOAMI_GUEST;
2669 /* NOTE: 8 bytes for UID/GID, irrespective of native
2670 * platform size. This matches
2671 * SMB_QUERY_FILE_UNIX_BASIC and friends.
2673 data_len = 4 /* flags */
2674 + 4 /* flag mask */
2675 + 8 /* uid */
2676 + 8 /* gid */
2677 + 4 /* ngroups */
2678 + 4 /* num_sids */
2679 + 4 /* SID bytes */
2680 + 4 /* pad/reserved */
2681 + (conn->session_info->unix_token->ngroups * 8)
2682 /* groups list */
2683 + (conn->session_info->security_token->num_sids *
2684 SID_MAX_SIZE)
2685 /* SID list */;
2687 SIVAL(pdata, 0, flags);
2688 SIVAL(pdata, 4, SMB_WHOAMI_MASK);
2689 SBIG_UINT(pdata, 8,
2690 (uint64_t)conn->session_info->unix_token->uid);
2691 SBIG_UINT(pdata, 16,
2692 (uint64_t)conn->session_info->unix_token->gid);
2695 if (data_len >= max_data_bytes) {
2696 /* Potential overflow, skip the GIDs and SIDs. */
2698 SIVAL(pdata, 24, 0); /* num_groups */
2699 SIVAL(pdata, 28, 0); /* num_sids */
2700 SIVAL(pdata, 32, 0); /* num_sid_bytes */
2701 SIVAL(pdata, 36, 0); /* reserved */
2703 data_len = 40;
2704 break;
2707 SIVAL(pdata, 24, conn->session_info->unix_token->ngroups);
2708 SIVAL(pdata, 28, conn->session_info->security_token->num_sids);
2710 /* We walk the SID list twice, but this call is fairly
2711 * infrequent, and I don't expect that it's performance
2712 * sensitive -- jpeach
2714 for (i = 0, sid_bytes = 0;
2715 i < conn->session_info->security_token->num_sids; ++i) {
2716 sid_bytes += ndr_size_dom_sid(
2717 &conn->session_info->security_token->sids[i],
2721 /* SID list byte count */
2722 SIVAL(pdata, 32, sid_bytes);
2724 /* 4 bytes pad/reserved - must be zero */
2725 SIVAL(pdata, 36, 0);
2726 data_len = 40;
2728 /* GID list */
2729 for (i = 0; i < conn->session_info->unix_token->ngroups; ++i) {
2730 SBIG_UINT(pdata, data_len,
2731 (uint64_t)conn->session_info->unix_token->groups[i]);
2732 data_len += 8;
2735 /* SID list */
2736 for (i = 0;
2737 i < conn->session_info->security_token->num_sids; ++i) {
2738 int sid_len = ndr_size_dom_sid(
2739 &conn->session_info->security_token->sids[i],
2742 sid_linearize((uint8_t *)(pdata + data_len),
2743 sid_len,
2744 &conn->session_info->security_token->sids[i]);
2745 data_len += sid_len;
2748 break;
2751 case SMB_MAC_QUERY_FS_INFO:
2753 * Thursby MAC extension... ONLY on NTFS filesystems
2754 * once we do streams then we don't need this
2756 if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
2757 data_len = 88;
2758 SIVAL(pdata,84,0x100); /* Don't support mac... */
2759 break;
2762 FALL_THROUGH;
2763 default:
2764 return NT_STATUS_INVALID_LEVEL;
2767 *ret_data_len = data_len;
2768 return status;
2771 NTSTATUS smb_set_fsquota(connection_struct *conn,
2772 struct smb_request *req,
2773 files_struct *fsp,
2774 const DATA_BLOB *qdata)
2776 const struct loadparm_substitution *lp_sub =
2777 loadparm_s3_global_substitution();
2778 NTSTATUS status;
2779 SMB_NTQUOTA_STRUCT quotas;
2781 ZERO_STRUCT(quotas);
2783 /* access check */
2784 if ((get_current_uid(conn) != 0) || !CAN_WRITE(conn)) {
2785 DEBUG(3, ("set_fsquota: access_denied service [%s] user [%s]\n",
2786 lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
2787 conn->session_info->unix_info->unix_name));
2788 return NT_STATUS_ACCESS_DENIED;
2791 if (!check_fsp_ntquota_handle(conn, req,
2792 fsp)) {
2793 DEBUG(1, ("set_fsquota: no valid QUOTA HANDLE\n"));
2794 return NT_STATUS_INVALID_HANDLE;
2797 /* note: normally there're 48 bytes,
2798 * but we didn't use the last 6 bytes for now
2799 * --metze
2801 if (qdata->length < 42) {
2802 DEBUG(0,("set_fsquota: requires total_data(%u) >= 42 bytes!\n",
2803 (unsigned int)qdata->length));
2804 return NT_STATUS_INVALID_PARAMETER;
2807 /* unknown_1 24 NULL bytes in pdata*/
2809 /* the soft quotas 8 bytes (uint64_t)*/
2810 quotas.softlim = BVAL(qdata->data,24);
2812 /* the hard quotas 8 bytes (uint64_t)*/
2813 quotas.hardlim = BVAL(qdata->data,32);
2815 /* quota_flags 2 bytes **/
2816 quotas.qflags = SVAL(qdata->data,40);
2818 /* unknown_2 6 NULL bytes follow*/
2820 /* now set the quotas */
2821 if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
2822 DEBUG(1, ("vfs_set_ntquota() failed for service [%s]\n",
2823 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2824 status = map_nt_error_from_unix(errno);
2825 } else {
2826 status = NT_STATUS_OK;
2828 return status;
2831 NTSTATUS smbd_do_setfsinfo(connection_struct *conn,
2832 struct smb_request *req,
2833 TALLOC_CTX *mem_ctx,
2834 uint16_t info_level,
2835 files_struct *fsp,
2836 const DATA_BLOB *pdata)
2838 switch (info_level) {
2839 case SMB_FS_QUOTA_INFORMATION:
2841 return smb_set_fsquota(conn,
2842 req,
2843 fsp,
2844 pdata);
2847 default:
2848 break;
2850 return NT_STATUS_INVALID_LEVEL;
2853 #if defined(HAVE_POSIX_ACLS)
2854 /****************************************************************************
2855 Utility function to count the number of entries in a POSIX acl.
2856 ****************************************************************************/
2858 static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
2860 unsigned int ace_count = 0;
2861 int entry_id = SMB_ACL_FIRST_ENTRY;
2862 SMB_ACL_ENTRY_T entry;
2864 while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2865 /* get_next... */
2866 if (entry_id == SMB_ACL_FIRST_ENTRY) {
2867 entry_id = SMB_ACL_NEXT_ENTRY;
2869 ace_count++;
2871 return ace_count;
2874 /****************************************************************************
2875 Utility function to marshall a POSIX acl into wire format.
2876 ****************************************************************************/
2878 static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
2880 int entry_id = SMB_ACL_FIRST_ENTRY;
2881 SMB_ACL_ENTRY_T entry;
2883 while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2884 SMB_ACL_TAG_T tagtype;
2885 SMB_ACL_PERMSET_T permset;
2886 unsigned char perms = 0;
2887 unsigned int own_grp;
2889 /* get_next... */
2890 if (entry_id == SMB_ACL_FIRST_ENTRY) {
2891 entry_id = SMB_ACL_NEXT_ENTRY;
2894 if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
2895 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
2896 return False;
2899 if (sys_acl_get_permset(entry, &permset) == -1) {
2900 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
2901 return False;
2904 perms |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
2905 perms |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
2906 perms |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
2908 SCVAL(pdata,1,perms);
2910 switch (tagtype) {
2911 case SMB_ACL_USER_OBJ:
2912 SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
2913 own_grp = (unsigned int)pst->st_ex_uid;
2914 SIVAL(pdata,2,own_grp);
2915 SIVAL(pdata,6,0);
2916 break;
2917 case SMB_ACL_USER:
2919 uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
2920 if (!puid) {
2921 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2922 return False;
2924 own_grp = (unsigned int)*puid;
2925 SCVAL(pdata,0,SMB_POSIX_ACL_USER);
2926 SIVAL(pdata,2,own_grp);
2927 SIVAL(pdata,6,0);
2928 break;
2930 case SMB_ACL_GROUP_OBJ:
2931 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
2932 own_grp = (unsigned int)pst->st_ex_gid;
2933 SIVAL(pdata,2,own_grp);
2934 SIVAL(pdata,6,0);
2935 break;
2936 case SMB_ACL_GROUP:
2938 gid_t *pgid= (gid_t *)sys_acl_get_qualifier(entry);
2939 if (!pgid) {
2940 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2941 return False;
2943 own_grp = (unsigned int)*pgid;
2944 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
2945 SIVAL(pdata,2,own_grp);
2946 SIVAL(pdata,6,0);
2947 break;
2949 case SMB_ACL_MASK:
2950 SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
2951 SIVAL(pdata,2,0xFFFFFFFF);
2952 SIVAL(pdata,6,0xFFFFFFFF);
2953 break;
2954 case SMB_ACL_OTHER:
2955 SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
2956 SIVAL(pdata,2,0xFFFFFFFF);
2957 SIVAL(pdata,6,0xFFFFFFFF);
2958 break;
2959 default:
2960 DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
2961 return False;
2963 pdata += SMB_POSIX_ACL_ENTRY_SIZE;
2966 return True;
2968 #endif
2970 /****************************************************************************
2971 Store the FILE_UNIX_BASIC info.
2972 ****************************************************************************/
2974 static char *store_file_unix_basic(connection_struct *conn,
2975 char *pdata,
2976 files_struct *fsp,
2977 const SMB_STRUCT_STAT *psbuf)
2979 dev_t devno;
2981 DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
2982 DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode));
2984 SOFF_T(pdata,0,get_file_size_stat(psbuf)); /* File size 64 Bit */
2985 pdata += 8;
2987 SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
2988 pdata += 8;
2990 put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, &psbuf->st_ex_ctime); /* Change Time 64 Bit */
2991 put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, &psbuf->st_ex_atime); /* Last access time 64 Bit */
2992 put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, &psbuf->st_ex_mtime); /* Last modification time 64 Bit */
2993 pdata += 24;
2995 SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */
2996 SIVAL(pdata,4,0);
2997 pdata += 8;
2999 SIVAL(pdata,0,psbuf->st_ex_gid); /* group id of owner */
3000 SIVAL(pdata,4,0);
3001 pdata += 8;
3003 SIVAL(pdata,0,unix_filetype(psbuf->st_ex_mode));
3004 pdata += 4;
3006 if (S_ISBLK(psbuf->st_ex_mode) || S_ISCHR(psbuf->st_ex_mode)) {
3007 devno = psbuf->st_ex_rdev;
3008 } else {
3009 devno = psbuf->st_ex_dev;
3012 SIVAL(pdata,0,unix_dev_major(devno)); /* Major device number if type is device */
3013 SIVAL(pdata,4,0);
3014 pdata += 8;
3016 SIVAL(pdata,0,unix_dev_minor(devno)); /* Minor device number if type is device */
3017 SIVAL(pdata,4,0);
3018 pdata += 8;
3020 SINO_T_VAL(pdata, 0, psbuf->st_ex_ino); /* inode number */
3021 pdata += 8;
3023 SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode)); /* Standard UNIX file permissions */
3024 SIVAL(pdata,4,0);
3025 pdata += 8;
3027 SIVAL(pdata,0,psbuf->st_ex_nlink); /* number of hard links */
3028 SIVAL(pdata,4,0);
3029 pdata += 8;
3031 return pdata;
3034 /* Forward and reverse mappings from the UNIX_INFO2 file flags field and
3035 * the chflags(2) (or equivalent) flags.
3037 * XXX: this really should be behind the VFS interface. To do this, we would
3038 * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field.
3039 * Each VFS module could then implement its own mapping as appropriate for the
3040 * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS.
3042 static const struct {unsigned stat_fflag; unsigned smb_fflag;}
3043 info2_flags_map[] =
3045 #ifdef UF_NODUMP
3046 { UF_NODUMP, EXT_DO_NOT_BACKUP },
3047 #endif
3049 #ifdef UF_IMMUTABLE
3050 { UF_IMMUTABLE, EXT_IMMUTABLE },
3051 #endif
3053 #ifdef UF_APPEND
3054 { UF_APPEND, EXT_OPEN_APPEND_ONLY },
3055 #endif
3057 #ifdef UF_HIDDEN
3058 { UF_HIDDEN, EXT_HIDDEN },
3059 #endif
3061 /* Do not remove. We need to guarantee that this array has at least one
3062 * entry to build on HP-UX.
3064 { 0, 0 }
3068 static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
3069 uint32_t *smb_fflags, uint32_t *smb_fmask)
3071 size_t i;
3073 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3074 *smb_fmask |= info2_flags_map[i].smb_fflag;
3075 if (psbuf->st_ex_flags & info2_flags_map[i].stat_fflag) {
3076 *smb_fflags |= info2_flags_map[i].smb_fflag;
3081 static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
3082 const uint32_t smb_fflags,
3083 const uint32_t smb_fmask,
3084 int *stat_fflags)
3086 uint32_t max_fmask = 0;
3087 size_t i;
3089 *stat_fflags = psbuf->st_ex_flags;
3091 /* For each flags requested in smb_fmask, check the state of the
3092 * corresponding flag in smb_fflags and set or clear the matching
3093 * stat flag.
3096 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3097 max_fmask |= info2_flags_map[i].smb_fflag;
3098 if (smb_fmask & info2_flags_map[i].smb_fflag) {
3099 if (smb_fflags & info2_flags_map[i].smb_fflag) {
3100 *stat_fflags |= info2_flags_map[i].stat_fflag;
3101 } else {
3102 *stat_fflags &= ~info2_flags_map[i].stat_fflag;
3107 /* If smb_fmask is asking to set any bits that are not supported by
3108 * our flag mappings, we should fail.
3110 if ((smb_fmask & max_fmask) != smb_fmask) {
3111 return False;
3114 return True;
3118 /* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition
3119 * of file flags and birth (create) time.
3121 static char *store_file_unix_basic_info2(connection_struct *conn,
3122 char *pdata,
3123 files_struct *fsp,
3124 const SMB_STRUCT_STAT *psbuf)
3126 uint32_t file_flags = 0;
3127 uint32_t flags_mask = 0;
3129 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
3131 /* Create (birth) time 64 bit */
3132 put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, &psbuf->st_ex_btime);
3133 pdata += 8;
3135 map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
3136 SIVAL(pdata, 0, file_flags); /* flags */
3137 SIVAL(pdata, 4, flags_mask); /* mask */
3138 pdata += 8;
3140 return pdata;
3143 static NTSTATUS marshall_stream_info(unsigned int num_streams,
3144 const struct stream_struct *streams,
3145 char *data,
3146 unsigned int max_data_bytes,
3147 unsigned int *data_size)
3149 unsigned int i;
3150 unsigned int ofs = 0;
3152 if (max_data_bytes < 32) {
3153 return NT_STATUS_INFO_LENGTH_MISMATCH;
3156 for (i = 0; i < num_streams; i++) {
3157 unsigned int next_offset;
3158 size_t namelen;
3159 smb_ucs2_t *namebuf;
3161 if (!push_ucs2_talloc(talloc_tos(), &namebuf,
3162 streams[i].name, &namelen) ||
3163 namelen <= 2)
3165 return NT_STATUS_INVALID_PARAMETER;
3169 * name_buf is now null-terminated, we need to marshall as not
3170 * terminated
3173 namelen -= 2;
3176 * We cannot overflow ...
3178 if ((ofs + 24 + namelen) > max_data_bytes) {
3179 DEBUG(10, ("refusing to overflow reply at stream %u\n",
3180 i));
3181 TALLOC_FREE(namebuf);
3182 return STATUS_BUFFER_OVERFLOW;
3185 SIVAL(data, ofs+4, namelen);
3186 SOFF_T(data, ofs+8, streams[i].size);
3187 SOFF_T(data, ofs+16, streams[i].alloc_size);
3188 memcpy(data+ofs+24, namebuf, namelen);
3189 TALLOC_FREE(namebuf);
3191 next_offset = ofs + 24 + namelen;
3193 if (i == num_streams-1) {
3194 SIVAL(data, ofs, 0);
3196 else {
3197 unsigned int align = ndr_align_size(next_offset, 8);
3199 if ((next_offset + align) > max_data_bytes) {
3200 DEBUG(10, ("refusing to overflow align "
3201 "reply at stream %u\n",
3202 i));
3203 TALLOC_FREE(namebuf);
3204 return STATUS_BUFFER_OVERFLOW;
3207 memset(data+next_offset, 0, align);
3208 next_offset += align;
3210 SIVAL(data, ofs, next_offset - ofs);
3211 ofs = next_offset;
3214 ofs = next_offset;
3217 DEBUG(10, ("max_data: %u, data_size: %u\n", max_data_bytes, ofs));
3219 *data_size = ofs;
3221 return NT_STATUS_OK;
3224 static NTSTATUS smb_unix_read_symlink(connection_struct *conn,
3225 struct smb_request *req,
3226 struct smb_filename *smb_fname,
3227 char *pdata,
3228 unsigned int data_size_in,
3229 unsigned int *pdata_size_out)
3231 NTSTATUS status;
3232 size_t len = 0;
3233 int link_len = 0;
3234 struct smb_filename *parent_fname = NULL;
3235 struct smb_filename *base_name = NULL;
3237 char *buffer = talloc_array(talloc_tos(), char, PATH_MAX+1);
3239 if (!buffer) {
3240 return NT_STATUS_NO_MEMORY;
3243 DBG_DEBUG("SMB_QUERY_FILE_UNIX_LINK for file %s\n",
3244 smb_fname_str_dbg(smb_fname));
3246 if(!S_ISLNK(smb_fname->st.st_ex_mode)) {
3247 TALLOC_FREE(buffer);
3248 return NT_STATUS_DOS(ERRSRV, ERRbadlink);
3251 status = parent_pathref(talloc_tos(),
3252 conn->cwd_fsp,
3253 smb_fname,
3254 &parent_fname,
3255 &base_name);
3256 if (!NT_STATUS_IS_OK(status)) {
3257 TALLOC_FREE(buffer);
3258 return status;
3261 link_len = SMB_VFS_READLINKAT(conn,
3262 parent_fname->fsp,
3263 base_name,
3264 buffer,
3265 PATH_MAX);
3267 TALLOC_FREE(parent_fname);
3269 if (link_len == -1) {
3270 TALLOC_FREE(buffer);
3271 return map_nt_error_from_unix(errno);
3274 buffer[link_len] = 0;
3275 status = srvstr_push(pdata,
3276 req->flags2,
3277 pdata,
3278 buffer,
3279 data_size_in,
3280 STR_TERMINATE,
3281 &len);
3282 TALLOC_FREE(buffer);
3283 if (!NT_STATUS_IS_OK(status)) {
3284 return status;
3286 *pdata_size_out = len;
3288 return NT_STATUS_OK;
3291 #if defined(HAVE_POSIX_ACLS)
3292 static NTSTATUS smb_query_posix_acl(connection_struct *conn,
3293 struct smb_request *req,
3294 files_struct *fsp,
3295 struct smb_filename *smb_fname,
3296 char *pdata,
3297 unsigned int data_size_in,
3298 unsigned int *pdata_size_out)
3300 SMB_ACL_T file_acl = NULL;
3301 SMB_ACL_T def_acl = NULL;
3302 uint16_t num_file_acls = 0;
3303 uint16_t num_def_acls = 0;
3304 unsigned int size_needed = 0;
3305 NTSTATUS status;
3306 bool ok;
3307 bool close_fsp = false;
3310 * Ensure we always operate on a file descriptor, not just
3311 * the filename.
3313 if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
3314 uint32_t access_mask = SEC_STD_READ_CONTROL|
3315 FILE_READ_ATTRIBUTES|
3316 FILE_WRITE_ATTRIBUTES;
3318 status = get_posix_fsp(conn,
3319 req,
3320 smb_fname,
3321 access_mask,
3322 &fsp);
3324 if (!NT_STATUS_IS_OK(status)) {
3325 goto out;
3327 close_fsp = true;
3330 SMB_ASSERT(fsp != NULL);
3332 status = refuse_symlink_fsp(fsp);
3333 if (!NT_STATUS_IS_OK(status)) {
3334 goto out;
3337 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, SMB_ACL_TYPE_ACCESS,
3338 talloc_tos());
3340 if (file_acl == NULL && no_acl_syscall_error(errno)) {
3341 DBG_INFO("ACLs not implemented on "
3342 "filesystem containing %s\n",
3343 fsp_str_dbg(fsp));
3344 status = NT_STATUS_NOT_IMPLEMENTED;
3345 goto out;
3348 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
3350 * We can only have default POSIX ACLs on
3351 * directories.
3353 if (!fsp->fsp_flags.is_directory) {
3354 DBG_INFO("Non-directory open %s\n",
3355 fsp_str_dbg(fsp));
3356 status = NT_STATUS_INVALID_HANDLE;
3357 goto out;
3359 def_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
3360 SMB_ACL_TYPE_DEFAULT,
3361 talloc_tos());
3362 def_acl = free_empty_sys_acl(conn, def_acl);
3365 num_file_acls = count_acl_entries(conn, file_acl);
3366 num_def_acls = count_acl_entries(conn, def_acl);
3368 /* Wrap checks. */
3369 if (num_file_acls + num_def_acls < num_file_acls) {
3370 status = NT_STATUS_INVALID_PARAMETER;
3371 goto out;
3374 size_needed = num_file_acls + num_def_acls;
3377 * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
3378 * than UINT_MAX, so check by division.
3380 if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
3381 status = NT_STATUS_INVALID_PARAMETER;
3382 goto out;
3385 size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
3386 if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
3387 status = NT_STATUS_INVALID_PARAMETER;
3388 goto out;
3390 size_needed += SMB_POSIX_ACL_HEADER_SIZE;
3392 if ( data_size_in < size_needed) {
3393 DBG_INFO("data_size too small (%u) need %u\n",
3394 data_size_in,
3395 size_needed);
3396 status = NT_STATUS_BUFFER_TOO_SMALL;
3397 goto out;
3400 SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
3401 SSVAL(pdata,2,num_file_acls);
3402 SSVAL(pdata,4,num_def_acls);
3403 pdata += SMB_POSIX_ACL_HEADER_SIZE;
3405 ok = marshall_posix_acl(conn,
3406 pdata,
3407 &fsp->fsp_name->st,
3408 file_acl);
3409 if (!ok) {
3410 status = NT_STATUS_INTERNAL_ERROR;
3411 goto out;
3413 pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
3415 ok = marshall_posix_acl(conn,
3416 pdata,
3417 &fsp->fsp_name->st,
3418 def_acl);
3419 if (!ok) {
3420 status = NT_STATUS_INTERNAL_ERROR;
3421 goto out;
3424 *pdata_size_out = size_needed;
3425 status = NT_STATUS_OK;
3427 out:
3429 if (close_fsp) {
3431 * Ensure the stat struct in smb_fname is up to
3432 * date. Structure copy.
3434 smb_fname->st = fsp->fsp_name->st;
3435 (void)close_file_free(req, &fsp, NORMAL_CLOSE);
3438 TALLOC_FREE(file_acl);
3439 TALLOC_FREE(def_acl);
3440 return status;
3442 #endif
3444 NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
3445 TALLOC_CTX *mem_ctx,
3446 struct smb_request *req,
3447 uint16_t info_level,
3448 files_struct *fsp,
3449 struct smb_filename *smb_fname,
3450 bool delete_pending,
3451 struct timespec write_time_ts,
3452 struct ea_list *ea_list,
3453 int lock_data_count,
3454 char *lock_data,
3455 uint16_t flags2,
3456 unsigned int max_data_bytes,
3457 size_t *fixed_portion,
3458 char **ppdata,
3459 unsigned int *pdata_size)
3461 char *pdata = *ppdata;
3462 char *dstart, *dend;
3463 unsigned int data_size;
3464 struct timespec create_time_ts, mtime_ts, atime_ts, ctime_ts;
3465 time_t create_time, mtime, atime, c_time;
3466 SMB_STRUCT_STAT *psbuf = NULL;
3467 SMB_STRUCT_STAT *base_sp = NULL;
3468 char *p;
3469 char *base_name;
3470 char *dos_fname;
3471 int mode;
3472 int nlink;
3473 NTSTATUS status;
3474 uint64_t file_size = 0;
3475 uint64_t pos = 0;
3476 uint64_t allocation_size = 0;
3477 uint64_t file_id = 0;
3478 uint32_t access_mask = 0;
3479 size_t len = 0;
3481 if (INFO_LEVEL_IS_UNIX(info_level)) {
3482 if (!lp_smb1_unix_extensions()) {
3483 return NT_STATUS_INVALID_LEVEL;
3485 if (!req->posix_pathnames) {
3486 return NT_STATUS_INVALID_LEVEL;
3490 DEBUG(5,("smbd_do_qfilepathinfo: %s (%s) level=%d max_data=%u\n",
3491 smb_fname_str_dbg(smb_fname),
3492 fsp_fnum_dbg(fsp),
3493 info_level, max_data_bytes));
3496 * In case of querying a symlink in POSIX context,
3497 * fsp will be NULL. fdos_mode() deals with it.
3499 if (fsp != NULL) {
3500 smb_fname = fsp->fsp_name;
3502 mode = fdos_mode(fsp);
3503 psbuf = &smb_fname->st;
3505 if (fsp != NULL) {
3506 base_sp = fsp->base_fsp ?
3507 &fsp->base_fsp->fsp_name->st :
3508 &fsp->fsp_name->st;
3509 } else {
3510 base_sp = &smb_fname->st;
3513 nlink = psbuf->st_ex_nlink;
3515 if (nlink && (mode&FILE_ATTRIBUTE_DIRECTORY)) {
3516 nlink = 1;
3519 if ((nlink > 0) && delete_pending) {
3520 nlink -= 1;
3523 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
3524 return NT_STATUS_INVALID_PARAMETER;
3527 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
3528 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
3529 if (*ppdata == NULL) {
3530 return NT_STATUS_NO_MEMORY;
3532 pdata = *ppdata;
3533 dstart = pdata;
3534 dend = dstart + data_size - 1;
3536 if (!is_omit_timespec(&write_time_ts) &&
3537 !INFO_LEVEL_IS_UNIX(info_level))
3539 update_stat_ex_mtime(psbuf, write_time_ts);
3542 create_time_ts = get_create_timespec(conn, fsp, smb_fname);
3543 mtime_ts = psbuf->st_ex_mtime;
3544 atime_ts = psbuf->st_ex_atime;
3545 ctime_ts = get_change_timespec(conn, fsp, smb_fname);
3547 if (lp_dos_filetime_resolution(SNUM(conn))) {
3548 dos_filetime_timespec(&create_time_ts);
3549 dos_filetime_timespec(&mtime_ts);
3550 dos_filetime_timespec(&atime_ts);
3551 dos_filetime_timespec(&ctime_ts);
3554 create_time = convert_timespec_to_time_t(create_time_ts);
3555 mtime = convert_timespec_to_time_t(mtime_ts);
3556 atime = convert_timespec_to_time_t(atime_ts);
3557 c_time = convert_timespec_to_time_t(ctime_ts);
3559 p = strrchr_m(smb_fname->base_name,'/');
3560 if (!p)
3561 base_name = smb_fname->base_name;
3562 else
3563 base_name = p+1;
3565 /* NT expects the name to be in an exact form of the *full*
3566 filename. See the trans2 torture test */
3567 if (ISDOT(base_name)) {
3568 dos_fname = talloc_strdup(mem_ctx, "\\");
3569 if (!dos_fname) {
3570 return NT_STATUS_NO_MEMORY;
3572 } else {
3573 dos_fname = talloc_asprintf(mem_ctx,
3574 "\\%s",
3575 smb_fname->base_name);
3576 if (!dos_fname) {
3577 return NT_STATUS_NO_MEMORY;
3579 if (is_named_stream(smb_fname)) {
3580 dos_fname = talloc_asprintf(dos_fname, "%s",
3581 smb_fname->stream_name);
3582 if (!dos_fname) {
3583 return NT_STATUS_NO_MEMORY;
3587 string_replace(dos_fname, '/', '\\');
3590 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, psbuf);
3592 if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
3593 /* Do we have this path open ? */
3594 files_struct *fsp1;
3595 struct file_id fileid = vfs_file_id_from_sbuf(conn, psbuf);
3596 fsp1 = file_find_di_first(conn->sconn, fileid, true);
3597 if (fsp1 && fsp1->initial_allocation_size) {
3598 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, psbuf);
3602 if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) {
3603 file_size = get_file_size_stat(psbuf);
3606 if (fsp) {
3607 pos = fh_get_position_information(fsp->fh);
3610 if (fsp) {
3611 access_mask = fsp->access_mask;
3612 } else {
3613 /* GENERIC_EXECUTE mapping from Windows */
3614 access_mask = 0x12019F;
3617 /* This should be an index number - looks like
3618 dev/ino to me :-)
3620 I think this causes us to fail the IFSKIT
3621 BasicFileInformationTest. -tpot */
3622 file_id = SMB_VFS_FS_FILE_ID(conn, base_sp);
3624 *fixed_portion = 0;
3626 switch (info_level) {
3627 case SMB_INFO_STANDARD:
3628 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
3629 data_size = 22;
3630 srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
3631 srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
3632 srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
3633 SIVAL(pdata,l1_cbFile,(uint32_t)file_size);
3634 SIVAL(pdata,l1_cbFileAlloc,(uint32_t)allocation_size);
3635 SSVAL(pdata,l1_attrFile,mode);
3636 break;
3638 case SMB_INFO_QUERY_EA_SIZE:
3640 unsigned int ea_size =
3641 estimate_ea_size(smb_fname->fsp);
3642 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
3643 data_size = 26;
3644 srv_put_dos_date2(pdata,0,create_time);
3645 srv_put_dos_date2(pdata,4,atime);
3646 srv_put_dos_date2(pdata,8,mtime); /* write time */
3647 SIVAL(pdata,12,(uint32_t)file_size);
3648 SIVAL(pdata,16,(uint32_t)allocation_size);
3649 SSVAL(pdata,20,mode);
3650 SIVAL(pdata,22,ea_size);
3651 break;
3654 case SMB_INFO_IS_NAME_VALID:
3655 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
3656 if (fsp) {
3657 /* os/2 needs this ? really ?*/
3658 return NT_STATUS_DOS(ERRDOS, ERRbadfunc);
3660 /* This is only reached for qpathinfo */
3661 data_size = 0;
3662 break;
3664 case SMB_INFO_QUERY_EAS_FROM_LIST:
3666 size_t total_ea_len = 0;
3667 struct ea_list *ea_file_list = NULL;
3668 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
3670 status =
3671 get_ea_list_from_fsp(mem_ctx,
3672 smb_fname->fsp,
3673 &total_ea_len, &ea_file_list);
3674 if (!NT_STATUS_IS_OK(status)) {
3675 return status;
3678 ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
3680 if (!ea_list || (total_ea_len > data_size)) {
3681 data_size = 4;
3682 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
3683 break;
3686 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
3687 break;
3690 case SMB_INFO_QUERY_ALL_EAS:
3692 /* We have data_size bytes to put EA's into. */
3693 size_t total_ea_len = 0;
3694 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
3696 status = get_ea_list_from_fsp(mem_ctx,
3697 smb_fname->fsp,
3698 &total_ea_len, &ea_list);
3699 if (!NT_STATUS_IS_OK(status)) {
3700 return status;
3703 if (!ea_list || (total_ea_len > data_size)) {
3704 data_size = 4;
3705 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
3706 break;
3709 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
3710 break;
3713 case SMB2_FILE_FULL_EA_INFORMATION:
3715 /* We have data_size bytes to put EA's into. */
3716 size_t total_ea_len = 0;
3717 struct ea_list *ea_file_list = NULL;
3719 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n"));
3721 /*TODO: add filtering and index handling */
3723 status =
3724 get_ea_list_from_fsp(mem_ctx,
3725 smb_fname->fsp,
3726 &total_ea_len, &ea_file_list);
3727 if (!NT_STATUS_IS_OK(status)) {
3728 return status;
3730 if (!ea_file_list) {
3731 return NT_STATUS_NO_EAS_ON_FILE;
3734 status = fill_ea_chained_buffer(mem_ctx,
3735 pdata,
3736 data_size,
3737 &data_size,
3738 conn, ea_file_list);
3739 if (!NT_STATUS_IS_OK(status)) {
3740 return status;
3742 break;
3745 case SMB_FILE_BASIC_INFORMATION:
3746 case SMB_QUERY_FILE_BASIC_INFO:
3748 if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
3749 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
3750 data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
3751 } else {
3752 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
3753 data_size = 40;
3754 SIVAL(pdata,36,0);
3756 put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
3757 put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
3758 put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
3759 put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
3760 SIVAL(pdata,32,mode);
3762 DEBUG(5,("SMB_QFBI - "));
3763 DEBUG(5,("create: %s ", ctime(&create_time)));
3764 DEBUG(5,("access: %s ", ctime(&atime)));
3765 DEBUG(5,("write: %s ", ctime(&mtime)));
3766 DEBUG(5,("change: %s ", ctime(&c_time)));
3767 DEBUG(5,("mode: %x\n", mode));
3768 *fixed_portion = data_size;
3769 break;
3771 case SMB_FILE_STANDARD_INFORMATION:
3772 case SMB_QUERY_FILE_STANDARD_INFO:
3774 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
3775 data_size = 24;
3776 SOFF_T(pdata,0,allocation_size);
3777 SOFF_T(pdata,8,file_size);
3778 SIVAL(pdata,16,nlink);
3779 SCVAL(pdata,20,delete_pending?1:0);
3780 SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
3781 SSVAL(pdata,22,0); /* Padding. */
3782 *fixed_portion = 24;
3783 break;
3785 case SMB_FILE_EA_INFORMATION:
3786 case SMB_QUERY_FILE_EA_INFO:
3788 unsigned int ea_size =
3789 estimate_ea_size(smb_fname->fsp);
3790 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
3791 data_size = 4;
3792 *fixed_portion = 4;
3793 SIVAL(pdata,0,ea_size);
3794 break;
3797 /* Get the 8.3 name - used if NT SMB was negotiated. */
3798 case SMB_QUERY_FILE_ALT_NAME_INFO:
3799 case SMB_FILE_ALTERNATE_NAME_INFORMATION:
3801 char mangled_name[13];
3802 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
3803 if (!name_to_8_3(base_name,mangled_name,
3804 True,conn->params)) {
3805 return NT_STATUS_NO_MEMORY;
3807 status = srvstr_push(dstart, flags2,
3808 pdata+4, mangled_name,
3809 PTR_DIFF(dend, pdata+4),
3810 STR_UNICODE, &len);
3811 if (!NT_STATUS_IS_OK(status)) {
3812 return status;
3814 data_size = 4 + len;
3815 SIVAL(pdata,0,len);
3816 *fixed_portion = 8;
3817 break;
3820 case SMB_QUERY_FILE_NAME_INFO:
3823 this must be *exactly* right for ACLs on mapped drives to work
3825 status = srvstr_push(dstart, flags2,
3826 pdata+4, dos_fname,
3827 PTR_DIFF(dend, pdata+4),
3828 STR_UNICODE, &len);
3829 if (!NT_STATUS_IS_OK(status)) {
3830 return status;
3832 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
3833 data_size = 4 + len;
3834 SIVAL(pdata,0,len);
3835 break;
3838 case SMB_FILE_NORMALIZED_NAME_INFORMATION:
3840 char *nfname = NULL;
3842 if (fsp == NULL || !fsp->conn->sconn->using_smb2) {
3843 return NT_STATUS_INVALID_LEVEL;
3846 nfname = talloc_strdup(mem_ctx, smb_fname->base_name);
3847 if (nfname == NULL) {
3848 return NT_STATUS_NO_MEMORY;
3851 if (ISDOT(nfname)) {
3852 nfname[0] = '\0';
3854 string_replace(nfname, '/', '\\');
3856 if (fsp_is_alternate_stream(fsp)) {
3857 const char *s = smb_fname->stream_name;
3858 const char *e = NULL;
3859 size_t n;
3861 SMB_ASSERT(s[0] != '\0');
3864 * smb_fname->stream_name is in form
3865 * of ':StrEam:$DATA', but we should only
3866 * append ':StrEam' here.
3869 e = strchr(&s[1], ':');
3870 if (e == NULL) {
3871 n = strlen(s);
3872 } else {
3873 n = PTR_DIFF(e, s);
3875 nfname = talloc_strndup_append(nfname, s, n);
3876 if (nfname == NULL) {
3877 return NT_STATUS_NO_MEMORY;
3881 status = srvstr_push(dstart, flags2,
3882 pdata+4, nfname,
3883 PTR_DIFF(dend, pdata+4),
3884 STR_UNICODE, &len);
3885 if (!NT_STATUS_IS_OK(status)) {
3886 return status;
3888 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NORMALIZED_NAME_INFORMATION\n"));
3889 data_size = 4 + len;
3890 SIVAL(pdata,0,len);
3891 *fixed_portion = 8;
3892 break;
3895 case SMB_FILE_ALLOCATION_INFORMATION:
3896 case SMB_QUERY_FILE_ALLOCATION_INFO:
3897 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
3898 data_size = 8;
3899 SOFF_T(pdata,0,allocation_size);
3900 break;
3902 case SMB_FILE_END_OF_FILE_INFORMATION:
3903 case SMB_QUERY_FILE_END_OF_FILEINFO:
3904 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
3905 data_size = 8;
3906 SOFF_T(pdata,0,file_size);
3907 break;
3909 case SMB_QUERY_FILE_ALL_INFO:
3910 case SMB_FILE_ALL_INFORMATION:
3912 unsigned int ea_size =
3913 estimate_ea_size(smb_fname->fsp);
3914 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
3915 put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
3916 put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
3917 put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
3918 put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
3919 SIVAL(pdata,32,mode);
3920 SIVAL(pdata,36,0); /* padding. */
3921 pdata += 40;
3922 SOFF_T(pdata,0,allocation_size);
3923 SOFF_T(pdata,8,file_size);
3924 SIVAL(pdata,16,nlink);
3925 SCVAL(pdata,20,delete_pending);
3926 SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
3927 SSVAL(pdata,22,0);
3928 pdata += 24;
3929 SIVAL(pdata,0,ea_size);
3930 pdata += 4; /* EA info */
3931 status = srvstr_push(dstart, flags2,
3932 pdata+4, dos_fname,
3933 PTR_DIFF(dend, pdata+4),
3934 STR_UNICODE, &len);
3935 if (!NT_STATUS_IS_OK(status)) {
3936 return status;
3938 SIVAL(pdata,0,len);
3939 pdata += 4 + len;
3940 data_size = PTR_DIFF(pdata,(*ppdata));
3941 *fixed_portion = 10;
3942 break;
3945 case SMB2_FILE_ALL_INFORMATION:
3947 unsigned int ea_size =
3948 estimate_ea_size(smb_fname->fsp);
3949 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
3950 put_long_date_full_timespec(conn->ts_res,pdata+0x00,&create_time_ts);
3951 put_long_date_full_timespec(conn->ts_res,pdata+0x08,&atime_ts);
3952 put_long_date_full_timespec(conn->ts_res,pdata+0x10,&mtime_ts); /* write time */
3953 put_long_date_full_timespec(conn->ts_res,pdata+0x18,&ctime_ts); /* change time */
3954 SIVAL(pdata, 0x20, mode);
3955 SIVAL(pdata, 0x24, 0); /* padding. */
3956 SBVAL(pdata, 0x28, allocation_size);
3957 SBVAL(pdata, 0x30, file_size);
3958 SIVAL(pdata, 0x38, nlink);
3959 SCVAL(pdata, 0x3C, delete_pending);
3960 SCVAL(pdata, 0x3D, (mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
3961 SSVAL(pdata, 0x3E, 0); /* padding */
3962 SBVAL(pdata, 0x40, file_id);
3963 SIVAL(pdata, 0x48, ea_size);
3964 SIVAL(pdata, 0x4C, access_mask);
3965 SBVAL(pdata, 0x50, pos);
3966 SIVAL(pdata, 0x58, mode); /*TODO: mode != mode fix this!!! */
3967 SIVAL(pdata, 0x5C, 0); /* No alignment needed. */
3969 pdata += 0x60;
3971 status = srvstr_push(dstart, flags2,
3972 pdata+4, dos_fname,
3973 PTR_DIFF(dend, pdata+4),
3974 STR_UNICODE, &len);
3975 if (!NT_STATUS_IS_OK(status)) {
3976 return status;
3978 SIVAL(pdata,0,len);
3979 pdata += 4 + len;
3980 data_size = PTR_DIFF(pdata,(*ppdata));
3981 *fixed_portion = 104;
3982 break;
3984 case SMB_FILE_INTERNAL_INFORMATION:
3986 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
3987 SBVAL(pdata, 0, file_id);
3988 data_size = 8;
3989 *fixed_portion = 8;
3990 break;
3992 case SMB_FILE_ACCESS_INFORMATION:
3993 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
3994 SIVAL(pdata, 0, access_mask);
3995 data_size = 4;
3996 *fixed_portion = 4;
3997 break;
3999 case SMB_FILE_NAME_INFORMATION:
4000 /* Pathname with leading '\'. */
4002 size_t byte_len;
4003 byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
4004 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
4005 SIVAL(pdata,0,byte_len);
4006 data_size = 4 + byte_len;
4007 break;
4010 case SMB_FILE_DISPOSITION_INFORMATION:
4011 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
4012 data_size = 1;
4013 SCVAL(pdata,0,delete_pending);
4014 *fixed_portion = 1;
4015 break;
4017 case SMB_FILE_POSITION_INFORMATION:
4018 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
4019 data_size = 8;
4020 SOFF_T(pdata,0,pos);
4021 *fixed_portion = 8;
4022 break;
4024 case SMB_FILE_MODE_INFORMATION:
4025 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
4026 SIVAL(pdata,0,mode);
4027 data_size = 4;
4028 *fixed_portion = 4;
4029 break;
4031 case SMB_FILE_ALIGNMENT_INFORMATION:
4032 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
4033 SIVAL(pdata,0,0); /* No alignment needed. */
4034 data_size = 4;
4035 *fixed_portion = 4;
4036 break;
4039 * NT4 server just returns "invalid query" to this - if we try
4040 * to answer it then NTws gets a BSOD! (tridge). W2K seems to
4041 * want this. JRA.
4043 /* The first statement above is false - verified using Thursby
4044 * client against NT4 -- gcolley.
4046 case SMB_QUERY_FILE_STREAM_INFO:
4047 case SMB_FILE_STREAM_INFORMATION: {
4048 unsigned int num_streams = 0;
4049 struct stream_struct *streams = NULL;
4051 DEBUG(10,("smbd_do_qfilepathinfo: "
4052 "SMB_FILE_STREAM_INFORMATION\n"));
4054 if (is_ntfs_stream_smb_fname(smb_fname)) {
4055 return NT_STATUS_INVALID_PARAMETER;
4058 status = vfs_fstreaminfo(fsp,
4059 mem_ctx,
4060 &num_streams,
4061 &streams);
4063 if (!NT_STATUS_IS_OK(status)) {
4064 DEBUG(10, ("could not get stream info: %s\n",
4065 nt_errstr(status)));
4066 return status;
4069 status = marshall_stream_info(num_streams, streams,
4070 pdata, max_data_bytes,
4071 &data_size);
4073 if (!NT_STATUS_IS_OK(status)) {
4074 DEBUG(10, ("marshall_stream_info failed: %s\n",
4075 nt_errstr(status)));
4076 TALLOC_FREE(streams);
4077 return status;
4080 TALLOC_FREE(streams);
4082 *fixed_portion = 32;
4084 break;
4086 case SMB_QUERY_COMPRESSION_INFO:
4087 case SMB_FILE_COMPRESSION_INFORMATION:
4088 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
4089 SOFF_T(pdata,0,file_size);
4090 SIVAL(pdata,8,0); /* ??? */
4091 SIVAL(pdata,12,0); /* ??? */
4092 data_size = 16;
4093 *fixed_portion = 16;
4094 break;
4096 case SMB_FILE_NETWORK_OPEN_INFORMATION:
4097 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
4098 put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
4099 put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
4100 put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
4101 put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
4102 SOFF_T(pdata,32,allocation_size);
4103 SOFF_T(pdata,40,file_size);
4104 SIVAL(pdata,48,mode);
4105 SIVAL(pdata,52,0); /* ??? */
4106 data_size = 56;
4107 *fixed_portion = 56;
4108 break;
4110 case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
4111 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
4112 SIVAL(pdata,0,mode);
4113 SIVAL(pdata,4,0);
4114 data_size = 8;
4115 *fixed_portion = 8;
4116 break;
4119 * CIFS UNIX Extensions.
4122 case SMB_QUERY_FILE_UNIX_BASIC:
4124 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
4125 data_size = PTR_DIFF(pdata,(*ppdata));
4127 DEBUG(4,("smbd_do_qfilepathinfo: "
4128 "SMB_QUERY_FILE_UNIX_BASIC\n"));
4129 dump_data(4, (uint8_t *)(*ppdata), data_size);
4131 break;
4133 case SMB_QUERY_FILE_UNIX_INFO2:
4135 pdata = store_file_unix_basic_info2(conn, pdata, fsp, psbuf);
4136 data_size = PTR_DIFF(pdata,(*ppdata));
4139 int i;
4140 DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));
4142 for (i=0; i<100; i++)
4143 DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
4144 DEBUG(4,("\n"));
4147 break;
4149 case SMB_QUERY_FILE_UNIX_LINK:
4151 status = smb_unix_read_symlink(conn,
4152 req,
4153 smb_fname,
4154 pdata,
4155 data_size,
4156 &data_size);
4157 if (!NT_STATUS_IS_OK(status)) {
4158 return status;
4160 break;
4163 #if defined(HAVE_POSIX_ACLS)
4164 case SMB_QUERY_POSIX_ACL:
4166 status = smb_query_posix_acl(conn,
4167 req,
4168 fsp,
4169 smb_fname,
4170 pdata,
4171 data_size,
4172 &data_size);
4173 if (!NT_STATUS_IS_OK(status)) {
4174 return status;
4176 break;
4178 #endif
4181 case SMB_QUERY_POSIX_LOCK:
4183 uint64_t count;
4184 uint64_t offset;
4185 uint64_t smblctx;
4186 enum brl_type lock_type;
4188 /* We need an open file with a real fd for this. */
4189 if (fsp == NULL ||
4190 fsp->fsp_flags.is_pathref ||
4191 fsp_get_io_fd(fsp) == -1)
4193 return NT_STATUS_INVALID_LEVEL;
4196 if (lock_data_count != POSIX_LOCK_DATA_SIZE) {
4197 return NT_STATUS_INVALID_PARAMETER;
4200 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
4201 case POSIX_LOCK_TYPE_READ:
4202 lock_type = READ_LOCK;
4203 break;
4204 case POSIX_LOCK_TYPE_WRITE:
4205 lock_type = WRITE_LOCK;
4206 break;
4207 case POSIX_LOCK_TYPE_UNLOCK:
4208 default:
4209 /* There's no point in asking for an unlock... */
4210 return NT_STATUS_INVALID_PARAMETER;
4213 smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
4214 offset = BVAL(pdata,POSIX_LOCK_START_OFFSET);
4215 count = BVAL(pdata,POSIX_LOCK_LEN_OFFSET);
4217 status = query_lock(fsp,
4218 &smblctx,
4219 &count,
4220 &offset,
4221 &lock_type,
4222 POSIX_LOCK);
4224 if (ERROR_WAS_LOCK_DENIED(status)) {
4225 /* Here we need to report who has it locked... */
4226 data_size = POSIX_LOCK_DATA_SIZE;
4228 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
4229 SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
4230 SIVAL(pdata, POSIX_LOCK_PID_OFFSET, (uint32_t)smblctx);
4231 SBVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
4232 SBVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
4234 } else if (NT_STATUS_IS_OK(status)) {
4235 /* For success we just return a copy of what we sent
4236 with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
4237 data_size = POSIX_LOCK_DATA_SIZE;
4238 memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
4239 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
4240 } else {
4241 return status;
4243 break;
4246 default:
4247 return NT_STATUS_INVALID_LEVEL;
4250 *pdata_size = data_size;
4251 return NT_STATUS_OK;
4254 /****************************************************************************
4255 Set a hard link (called by UNIX extensions and by NT rename with HARD link
4256 code.
4257 ****************************************************************************/
4259 NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
4260 connection_struct *conn,
4261 struct smb_request *req,
4262 bool overwrite_if_exists,
4263 struct files_struct *old_dirfsp,
4264 const struct smb_filename *smb_fname_old,
4265 struct files_struct *new_dirfsp,
4266 struct smb_filename *smb_fname_new)
4268 NTSTATUS status = NT_STATUS_OK;
4269 int ret;
4270 bool ok;
4271 struct smb_filename *parent_fname_old = NULL;
4272 struct smb_filename *base_name_old = NULL;
4273 struct smb_filename *parent_fname_new = NULL;
4274 struct smb_filename *base_name_new = NULL;
4276 /* source must already exist. */
4277 if (!VALID_STAT(smb_fname_old->st)) {
4278 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
4279 goto out;
4282 /* No links from a directory. */
4283 if (S_ISDIR(smb_fname_old->st.st_ex_mode)) {
4284 status = NT_STATUS_FILE_IS_A_DIRECTORY;
4285 goto out;
4288 /* Setting a hardlink to/from a stream isn't currently supported. */
4289 ok = is_ntfs_stream_smb_fname(smb_fname_old);
4290 if (ok) {
4291 DBG_DEBUG("Old name has streams\n");
4292 status = NT_STATUS_INVALID_PARAMETER;
4293 goto out;
4295 ok = is_ntfs_stream_smb_fname(smb_fname_new);
4296 if (ok) {
4297 DBG_DEBUG("New name has streams\n");
4298 status = NT_STATUS_INVALID_PARAMETER;
4299 goto out;
4302 status = parent_pathref(talloc_tos(),
4303 conn->cwd_fsp,
4304 smb_fname_old,
4305 &parent_fname_old,
4306 &base_name_old);
4307 if (!NT_STATUS_IS_OK(status)) {
4308 goto out;
4311 status = parent_pathref(talloc_tos(),
4312 conn->cwd_fsp,
4313 smb_fname_new,
4314 &parent_fname_new,
4315 &base_name_new);
4316 if (!NT_STATUS_IS_OK(status)) {
4317 goto out;
4320 if (VALID_STAT(smb_fname_new->st)) {
4321 if (overwrite_if_exists) {
4322 if (S_ISDIR(smb_fname_new->st.st_ex_mode)) {
4323 status = NT_STATUS_FILE_IS_A_DIRECTORY;
4324 goto out;
4326 status = unlink_internals(conn,
4327 req,
4328 FILE_ATTRIBUTE_NORMAL,
4329 NULL, /* new_dirfsp */
4330 smb_fname_new);
4331 if (!NT_STATUS_IS_OK(status)) {
4332 goto out;
4334 } else {
4335 /* Disallow if newname already exists. */
4336 status = NT_STATUS_OBJECT_NAME_COLLISION;
4337 goto out;
4341 DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n",
4342 smb_fname_old->base_name, smb_fname_new->base_name));
4344 ret = SMB_VFS_LINKAT(conn,
4345 parent_fname_old->fsp,
4346 base_name_old,
4347 parent_fname_new->fsp,
4348 base_name_new,
4351 if (ret != 0) {
4352 status = map_nt_error_from_unix(errno);
4353 DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
4354 nt_errstr(status), smb_fname_old->base_name,
4355 smb_fname_new->base_name));
4358 out:
4360 TALLOC_FREE(parent_fname_old);
4361 TALLOC_FREE(parent_fname_new);
4362 return status;
4365 /****************************************************************************
4366 Deal with setting the time from any of the setfilepathinfo functions.
4367 NOTE !!!! The check for FILE_WRITE_ATTRIBUTES access must be done *before*
4368 calling this function.
4369 ****************************************************************************/
4371 NTSTATUS smb_set_file_time(connection_struct *conn,
4372 files_struct *fsp,
4373 struct smb_filename *smb_fname,
4374 struct smb_file_time *ft,
4375 bool setting_write_time)
4377 struct files_struct *set_fsp = NULL;
4378 struct timeval_buf tbuf[4];
4379 uint32_t action =
4380 FILE_NOTIFY_CHANGE_LAST_ACCESS
4381 |FILE_NOTIFY_CHANGE_LAST_WRITE
4382 |FILE_NOTIFY_CHANGE_CREATION;
4383 int ret;
4385 if (!VALID_STAT(smb_fname->st)) {
4386 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4389 if (fsp == NULL) {
4390 /* A symlink */
4391 return NT_STATUS_OK;
4394 set_fsp = metadata_fsp(fsp);
4396 /* get some defaults (no modifications) if any info is zero or -1. */
4397 if (is_omit_timespec(&ft->create_time)) {
4398 action &= ~FILE_NOTIFY_CHANGE_CREATION;
4401 if (is_omit_timespec(&ft->atime)) {
4402 action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
4405 if (is_omit_timespec(&ft->mtime)) {
4406 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
4409 if (!setting_write_time) {
4410 /* ft->mtime comes from change time, not write time. */
4411 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
4414 /* Ensure the resolution is the correct for
4415 * what we can store on this filesystem. */
4417 round_timespec(conn->ts_res, &ft->create_time);
4418 round_timespec(conn->ts_res, &ft->ctime);
4419 round_timespec(conn->ts_res, &ft->atime);
4420 round_timespec(conn->ts_res, &ft->mtime);
4422 DBG_DEBUG("smb_set_filetime: actime: %s\n ",
4423 timespec_string_buf(&ft->atime, true, &tbuf[0]));
4424 DBG_DEBUG("smb_set_filetime: modtime: %s\n ",
4425 timespec_string_buf(&ft->mtime, true, &tbuf[1]));
4426 DBG_DEBUG("smb_set_filetime: ctime: %s\n ",
4427 timespec_string_buf(&ft->ctime, true, &tbuf[2]));
4428 DBG_DEBUG("smb_set_file_time: createtime: %s\n ",
4429 timespec_string_buf(&ft->create_time, true, &tbuf[3]));
4431 if (setting_write_time) {
4433 * This was a Windows setfileinfo on an open file.
4434 * NT does this a lot. We also need to
4435 * set the time here, as it can be read by
4436 * FindFirst/FindNext and with the patch for bug #2045
4437 * in smbd/fileio.c it ensures that this timestamp is
4438 * kept sticky even after a write. We save the request
4439 * away and will set it on file close and after a write. JRA.
4442 DBG_DEBUG("setting pending modtime to %s\n",
4443 timespec_string_buf(&ft->mtime, true, &tbuf[0]));
4445 if (set_fsp != NULL) {
4446 set_sticky_write_time_fsp(set_fsp, ft->mtime);
4447 } else {
4448 set_sticky_write_time_path(
4449 vfs_file_id_from_sbuf(conn, &smb_fname->st),
4450 ft->mtime);
4454 DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
4456 ret = file_ntimes(conn, set_fsp, ft);
4457 if (ret != 0) {
4458 return map_nt_error_from_unix(errno);
4461 notify_fname(conn, NOTIFY_ACTION_MODIFIED, action,
4462 smb_fname->base_name);
4463 return NT_STATUS_OK;
4466 /****************************************************************************
4467 Deal with setting the dosmode from any of the setfilepathinfo functions.
4468 NB. The check for FILE_WRITE_ATTRIBUTES access on this path must have been
4469 done before calling this function.
4470 ****************************************************************************/
4472 static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
4473 struct files_struct *fsp,
4474 uint32_t dosmode)
4476 struct files_struct *dos_fsp = NULL;
4477 uint32_t current_dosmode;
4478 int ret;
4480 if (!VALID_STAT(fsp->fsp_name->st)) {
4481 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4484 dos_fsp = metadata_fsp(fsp);
4486 if (dosmode != 0) {
4487 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
4488 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
4489 } else {
4490 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
4494 DBG_DEBUG("dosmode: 0x%" PRIx32 "\n", dosmode);
4496 /* check the mode isn't different, before changing it */
4497 if (dosmode == 0) {
4498 return NT_STATUS_OK;
4500 current_dosmode = fdos_mode(dos_fsp);
4501 if (dosmode == current_dosmode) {
4502 return NT_STATUS_OK;
4505 DBG_DEBUG("file %s : setting dos mode 0x%" PRIx32 "\n",
4506 fsp_str_dbg(dos_fsp), dosmode);
4508 ret = file_set_dosmode(conn, dos_fsp->fsp_name, dosmode, NULL, false);
4509 if (ret != 0) {
4510 DBG_WARNING("file_set_dosmode of %s failed: %s\n",
4511 fsp_str_dbg(dos_fsp), strerror(errno));
4512 return map_nt_error_from_unix(errno);
4515 return NT_STATUS_OK;
4518 /****************************************************************************
4519 Deal with setting the size from any of the setfilepathinfo functions.
4520 ****************************************************************************/
4522 static NTSTATUS smb_set_file_size(connection_struct *conn,
4523 struct smb_request *req,
4524 files_struct *fsp,
4525 struct smb_filename *smb_fname,
4526 const SMB_STRUCT_STAT *psbuf,
4527 off_t size,
4528 bool fail_after_createfile)
4530 NTSTATUS status = NT_STATUS_OK;
4531 files_struct *new_fsp = NULL;
4533 if (!VALID_STAT(*psbuf)) {
4534 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4537 DBG_INFO("size: %"PRIu64", file_size_stat=%"PRIu64"\n",
4538 (uint64_t)size,
4539 get_file_size_stat(psbuf));
4541 if (size == get_file_size_stat(psbuf)) {
4542 if (fsp == NULL) {
4543 return NT_STATUS_OK;
4545 if (!fsp->fsp_flags.modified) {
4546 return NT_STATUS_OK;
4548 trigger_write_time_update_immediate(fsp);
4549 return NT_STATUS_OK;
4552 DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n",
4553 smb_fname_str_dbg(smb_fname), (double)size));
4555 if (fsp &&
4556 !fsp->fsp_flags.is_pathref &&
4557 fsp_get_io_fd(fsp) != -1)
4559 /* Handle based call. */
4560 if (!(fsp->access_mask & FILE_WRITE_DATA)) {
4561 return NT_STATUS_ACCESS_DENIED;
4564 if (vfs_set_filelen(fsp, size) == -1) {
4565 return map_nt_error_from_unix(errno);
4567 trigger_write_time_update_immediate(fsp);
4568 return NT_STATUS_OK;
4571 status = SMB_VFS_CREATE_FILE(
4572 conn, /* conn */
4573 req, /* req */
4574 NULL, /* dirfsp */
4575 smb_fname, /* fname */
4576 FILE_WRITE_DATA, /* access_mask */
4577 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
4578 FILE_SHARE_DELETE),
4579 FILE_OPEN, /* create_disposition*/
4580 0, /* create_options */
4581 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
4582 0, /* oplock_request */
4583 NULL, /* lease */
4584 0, /* allocation_size */
4585 0, /* private_flags */
4586 NULL, /* sd */
4587 NULL, /* ea_list */
4588 &new_fsp, /* result */
4589 NULL, /* pinfo */
4590 NULL, NULL); /* create context */
4592 if (!NT_STATUS_IS_OK(status)) {
4593 /* NB. We check for open_was_deferred in the caller. */
4594 return status;
4597 /* See RAW-SFILEINFO-END-OF-FILE */
4598 if (fail_after_createfile) {
4599 close_file_free(req, &new_fsp, NORMAL_CLOSE);
4600 return NT_STATUS_INVALID_LEVEL;
4603 if (vfs_set_filelen(new_fsp, size) == -1) {
4604 status = map_nt_error_from_unix(errno);
4605 close_file_free(req, &new_fsp, NORMAL_CLOSE);
4606 return status;
4609 trigger_write_time_update_immediate(new_fsp);
4610 close_file_free(req, &new_fsp, NORMAL_CLOSE);
4611 return NT_STATUS_OK;
4614 /****************************************************************************
4615 Deal with SMB_INFO_SET_EA.
4616 ****************************************************************************/
4618 static NTSTATUS smb_info_set_ea(connection_struct *conn,
4619 const char *pdata,
4620 int total_data,
4621 files_struct *fsp,
4622 struct smb_filename *smb_fname)
4624 struct ea_list *ea_list = NULL;
4625 TALLOC_CTX *ctx = NULL;
4626 NTSTATUS status = NT_STATUS_OK;
4628 if (total_data < 10) {
4630 /* OS/2 workplace shell seems to send SET_EA requests of "null"
4631 length. They seem to have no effect. Bug #3212. JRA */
4633 if ((total_data == 4) && (IVAL(pdata,0) == 4)) {
4634 /* We're done. We only get EA info in this call. */
4635 return NT_STATUS_OK;
4638 return NT_STATUS_INVALID_PARAMETER;
4641 if (IVAL(pdata,0) > total_data) {
4642 DEBUG(10,("smb_info_set_ea: bad total data size (%u) > %u\n",
4643 IVAL(pdata,0), (unsigned int)total_data));
4644 return NT_STATUS_INVALID_PARAMETER;
4647 ctx = talloc_tos();
4648 ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
4649 if (!ea_list) {
4650 return NT_STATUS_INVALID_PARAMETER;
4653 if (fsp == NULL) {
4655 * The only way fsp can be NULL here is if
4656 * smb_fname points at a symlink and
4657 * and we're in POSIX context.
4658 * Ensure this is the case.
4660 * In this case we cannot set the EA.
4662 SMB_ASSERT(smb_fname->flags & SMB_FILENAME_POSIX_PATH);
4663 return NT_STATUS_ACCESS_DENIED;
4666 status = set_ea(conn, fsp, ea_list);
4668 return status;
4671 /****************************************************************************
4672 Deal with SMB_FILE_FULL_EA_INFORMATION set.
4673 ****************************************************************************/
4675 static NTSTATUS smb_set_file_full_ea_info(connection_struct *conn,
4676 const char *pdata,
4677 int total_data,
4678 files_struct *fsp)
4680 struct ea_list *ea_list = NULL;
4681 NTSTATUS status;
4683 if (fsp == NULL) {
4684 return NT_STATUS_INVALID_HANDLE;
4687 if (!lp_ea_support(SNUM(conn))) {
4688 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u but "
4689 "EA's not supported.\n",
4690 (unsigned int)total_data));
4691 return NT_STATUS_EAS_NOT_SUPPORTED;
4694 if (total_data < 10) {
4695 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u "
4696 "too small.\n",
4697 (unsigned int)total_data));
4698 return NT_STATUS_INVALID_PARAMETER;
4701 ea_list = read_nttrans_ea_list(talloc_tos(),
4702 pdata,
4703 total_data);
4705 if (!ea_list) {
4706 return NT_STATUS_INVALID_PARAMETER;
4709 status = set_ea(conn, fsp, ea_list);
4711 DEBUG(10, ("smb_set_file_full_ea_info on file %s returned %s\n",
4712 smb_fname_str_dbg(fsp->fsp_name),
4713 nt_errstr(status) ));
4715 return status;
4719 /****************************************************************************
4720 Deal with SMB_SET_FILE_DISPOSITION_INFO.
4721 ****************************************************************************/
4723 static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
4724 const char *pdata,
4725 int total_data,
4726 files_struct *fsp,
4727 struct smb_filename *smb_fname)
4729 NTSTATUS status = NT_STATUS_OK;
4730 bool delete_on_close;
4731 uint32_t dosmode = 0;
4733 if (total_data < 1) {
4734 return NT_STATUS_INVALID_PARAMETER;
4737 if (fsp == NULL) {
4738 return NT_STATUS_INVALID_HANDLE;
4741 delete_on_close = (CVAL(pdata,0) ? True : False);
4742 dosmode = fdos_mode(fsp);
4744 DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
4745 "delete_on_close = %u\n",
4746 smb_fname_str_dbg(smb_fname),
4747 (unsigned int)dosmode,
4748 (unsigned int)delete_on_close ));
4750 if (delete_on_close) {
4751 status = can_set_delete_on_close(fsp, dosmode);
4752 if (!NT_STATUS_IS_OK(status)) {
4753 return status;
4757 /* The set is across all open files on this dev/inode pair. */
4758 if (!set_delete_on_close(fsp, delete_on_close,
4759 conn->session_info->security_token,
4760 conn->session_info->unix_token)) {
4761 return NT_STATUS_ACCESS_DENIED;
4763 return NT_STATUS_OK;
4766 /****************************************************************************
4767 Deal with SMB_FILE_POSITION_INFORMATION.
4768 ****************************************************************************/
4770 static NTSTATUS smb_file_position_information(connection_struct *conn,
4771 const char *pdata,
4772 int total_data,
4773 files_struct *fsp)
4775 uint64_t position_information;
4777 if (total_data < 8) {
4778 return NT_STATUS_INVALID_PARAMETER;
4781 if (fsp == NULL) {
4782 /* Ignore on pathname based set. */
4783 return NT_STATUS_OK;
4786 position_information = (uint64_t)IVAL(pdata,0);
4787 position_information |= (((uint64_t)IVAL(pdata,4)) << 32);
4789 DEBUG(10,("smb_file_position_information: Set file position "
4790 "information for file %s to %.0f\n", fsp_str_dbg(fsp),
4791 (double)position_information));
4792 fh_set_position_information(fsp->fh, position_information);
4793 return NT_STATUS_OK;
4796 /****************************************************************************
4797 Deal with SMB_FILE_MODE_INFORMATION.
4798 ****************************************************************************/
4800 static NTSTATUS smb_file_mode_information(connection_struct *conn,
4801 const char *pdata,
4802 int total_data)
4804 uint32_t mode;
4806 if (total_data < 4) {
4807 return NT_STATUS_INVALID_PARAMETER;
4809 mode = IVAL(pdata,0);
4810 if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
4811 return NT_STATUS_INVALID_PARAMETER;
4813 return NT_STATUS_OK;
4816 /****************************************************************************
4817 Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
4818 ****************************************************************************/
4820 static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
4821 struct smb_request *req,
4822 const char *pdata,
4823 int total_data,
4824 struct smb_filename *new_smb_fname)
4826 char *link_target = NULL;
4827 struct smb_filename target_fname;
4828 TALLOC_CTX *ctx = talloc_tos();
4829 NTSTATUS status;
4830 int ret;
4831 struct smb_filename *parent_fname = NULL;
4832 struct smb_filename *base_name = NULL;
4834 /* Set a symbolic link. */
4835 /* Don't allow this if follow links is false. */
4837 if (total_data == 0) {
4838 return NT_STATUS_INVALID_PARAMETER;
4841 if (!lp_follow_symlinks(SNUM(conn))) {
4842 return NT_STATUS_ACCESS_DENIED;
4845 srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
4846 total_data, STR_TERMINATE);
4848 if (!link_target) {
4849 return NT_STATUS_INVALID_PARAMETER;
4852 target_fname = (struct smb_filename) {
4853 .base_name = link_target,
4856 /* Removes @GMT tokens if any */
4857 status = canonicalize_snapshot_path(&target_fname, UCF_GMT_PATHNAME, 0);
4858 if (!NT_STATUS_IS_OK(status)) {
4859 return status;
4862 DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
4863 new_smb_fname->base_name, link_target ));
4865 status = parent_pathref(talloc_tos(),
4866 conn->cwd_fsp,
4867 new_smb_fname,
4868 &parent_fname,
4869 &base_name);
4870 if (!NT_STATUS_IS_OK(status)) {
4871 return status;
4874 ret = SMB_VFS_SYMLINKAT(conn,
4875 &target_fname,
4876 parent_fname->fsp,
4877 base_name);
4878 if (ret != 0) {
4879 TALLOC_FREE(parent_fname);
4880 return map_nt_error_from_unix(errno);
4883 TALLOC_FREE(parent_fname);
4884 return NT_STATUS_OK;
4887 /****************************************************************************
4888 Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
4889 ****************************************************************************/
4891 static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
4892 struct smb_request *req,
4893 const char *pdata, int total_data,
4894 struct smb_filename *smb_fname_new)
4896 char *oldname = NULL;
4897 struct files_struct *src_dirfsp = NULL;
4898 struct smb_filename *smb_fname_old = NULL;
4899 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4900 NTTIME old_twrp = 0;
4901 TALLOC_CTX *ctx = talloc_tos();
4902 NTSTATUS status = NT_STATUS_OK;
4904 /* Set a hard link. */
4905 if (total_data == 0) {
4906 return NT_STATUS_INVALID_PARAMETER;
4909 if (req->posix_pathnames) {
4910 srvstr_get_path_posix(ctx,
4911 pdata,
4912 req->flags2,
4913 &oldname,
4914 pdata,
4915 total_data,
4916 STR_TERMINATE,
4917 &status);
4918 } else {
4919 srvstr_get_path(ctx,
4920 pdata,
4921 req->flags2,
4922 &oldname,
4923 pdata,
4924 total_data,
4925 STR_TERMINATE,
4926 &status);
4928 if (!NT_STATUS_IS_OK(status)) {
4929 return status;
4932 DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
4933 smb_fname_str_dbg(smb_fname_new), oldname));
4935 if (ucf_flags & UCF_GMT_PATHNAME) {
4936 extract_snapshot_token(oldname, &old_twrp);
4938 status = filename_convert_dirfsp(ctx,
4939 conn,
4940 oldname,
4941 ucf_flags,
4942 old_twrp,
4943 &src_dirfsp,
4944 &smb_fname_old);
4945 if (!NT_STATUS_IS_OK(status)) {
4946 return status;
4949 return hardlink_internals(ctx,
4950 conn,
4951 req,
4952 false,
4953 src_dirfsp,
4954 smb_fname_old,
4955 NULL, /* new_dirfsp */
4956 smb_fname_new);
4959 /****************************************************************************
4960 Deal with SMB2_FILE_RENAME_INFORMATION_INTERNAL
4961 ****************************************************************************/
4963 static NTSTATUS smb2_file_rename_information(connection_struct *conn,
4964 struct smb_request *req,
4965 const char *pdata,
4966 int total_data,
4967 files_struct *fsp,
4968 struct smb_filename *smb_fname_src)
4970 bool overwrite;
4971 uint32_t len;
4972 char *newname = NULL;
4973 struct files_struct *dst_dirfsp = NULL;
4974 struct smb_filename *smb_fname_dst = NULL;
4975 const char *dst_original_lcomp = NULL;
4976 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4977 NTTIME dst_twrp = 0;
4978 NTSTATUS status = NT_STATUS_OK;
4979 bool is_dfs = (req->flags2 & FLAGS2_DFS_PATHNAMES);
4980 TALLOC_CTX *ctx = talloc_tos();
4982 if (!fsp) {
4983 return NT_STATUS_INVALID_HANDLE;
4986 if (total_data < 20) {
4987 return NT_STATUS_INVALID_PARAMETER;
4990 overwrite = (CVAL(pdata,0) ? True : False);
4991 len = IVAL(pdata,16);
4993 if (len > (total_data - 20) || (len == 0)) {
4994 return NT_STATUS_INVALID_PARAMETER;
4997 (void)srvstr_pull_talloc(ctx,
4998 pdata,
4999 req->flags2,
5000 &newname,
5001 &pdata[20],
5002 len,
5003 STR_TERMINATE);
5005 if (newname == NULL) {
5006 return NT_STATUS_INVALID_PARAMETER;
5008 status = check_path_syntax_smb2(newname, is_dfs);
5009 if (!NT_STATUS_IS_OK(status)) {
5010 return status;
5013 DEBUG(10,("smb2_file_rename_information: got name |%s|\n",
5014 newname));
5016 if (newname[0] == ':') {
5017 /* Create an smb_fname to call rename_internals_fsp() with. */
5018 smb_fname_dst = synthetic_smb_fname(talloc_tos(),
5019 fsp->base_fsp->fsp_name->base_name,
5020 newname,
5021 NULL,
5022 fsp->base_fsp->fsp_name->twrp,
5023 fsp->base_fsp->fsp_name->flags);
5024 if (smb_fname_dst == NULL) {
5025 status = NT_STATUS_NO_MEMORY;
5026 goto out;
5028 } else {
5029 if (ucf_flags & UCF_GMT_PATHNAME) {
5030 extract_snapshot_token(newname, &dst_twrp);
5032 status = filename_convert_dirfsp(ctx,
5033 conn,
5034 newname,
5035 ucf_flags,
5036 dst_twrp,
5037 &dst_dirfsp,
5038 &smb_fname_dst);
5039 if (!NT_STATUS_IS_OK(status)) {
5040 goto out;
5045 * Set the original last component, since
5046 * rename_internals_fsp() requires it.
5048 dst_original_lcomp = get_original_lcomp(smb_fname_dst,
5049 conn,
5050 newname,
5051 ucf_flags);
5052 if (dst_original_lcomp == NULL) {
5053 status = NT_STATUS_NO_MEMORY;
5054 goto out;
5057 DEBUG(10,("smb2_file_rename_information: "
5058 "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
5059 fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
5060 smb_fname_str_dbg(smb_fname_dst)));
5061 status = rename_internals_fsp(conn,
5062 fsp,
5063 NULL, /* dst_dirfsp */
5064 smb_fname_dst,
5065 dst_original_lcomp,
5066 (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM),
5067 overwrite);
5069 out:
5070 TALLOC_FREE(smb_fname_dst);
5071 return status;
5074 static NTSTATUS smb_file_link_information(connection_struct *conn,
5075 struct smb_request *req,
5076 const char *pdata,
5077 int total_data,
5078 files_struct *fsp,
5079 struct smb_filename *smb_fname_src)
5081 bool overwrite;
5082 uint32_t len;
5083 char *newname = NULL;
5084 struct files_struct *dst_dirfsp = NULL;
5085 struct smb_filename *smb_fname_dst = NULL;
5086 NTSTATUS status = NT_STATUS_OK;
5087 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
5088 NTTIME dst_twrp = 0;
5089 TALLOC_CTX *ctx = talloc_tos();
5091 if (!fsp) {
5092 return NT_STATUS_INVALID_HANDLE;
5095 if (total_data < 20) {
5096 return NT_STATUS_INVALID_PARAMETER;
5099 overwrite = (CVAL(pdata,0) ? true : false);
5100 len = IVAL(pdata,16);
5102 if (len > (total_data - 20) || (len == 0)) {
5103 return NT_STATUS_INVALID_PARAMETER;
5106 if (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH) {
5107 srvstr_get_path_posix(ctx,
5108 pdata,
5109 req->flags2,
5110 &newname,
5111 &pdata[20],
5112 len,
5113 STR_TERMINATE,
5114 &status);
5115 ucf_flags |= UCF_POSIX_PATHNAMES;
5116 } else {
5117 srvstr_get_path(ctx,
5118 pdata,
5119 req->flags2,
5120 &newname,
5121 &pdata[20],
5122 len,
5123 STR_TERMINATE,
5124 &status);
5126 if (!NT_STATUS_IS_OK(status)) {
5127 return status;
5130 DEBUG(10,("smb_file_link_information: got name |%s|\n",
5131 newname));
5133 if (ucf_flags & UCF_GMT_PATHNAME) {
5134 extract_snapshot_token(newname, &dst_twrp);
5136 status = filename_convert_dirfsp(ctx,
5137 conn,
5138 newname,
5139 ucf_flags,
5140 dst_twrp,
5141 &dst_dirfsp,
5142 &smb_fname_dst);
5143 if (!NT_STATUS_IS_OK(status)) {
5144 return status;
5147 if (fsp->base_fsp) {
5148 /* No stream names. */
5149 return NT_STATUS_NOT_SUPPORTED;
5152 DEBUG(10,("smb_file_link_information: "
5153 "SMB_FILE_LINK_INFORMATION (%s) %s -> %s\n",
5154 fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
5155 smb_fname_str_dbg(smb_fname_dst)));
5156 status = hardlink_internals(ctx,
5157 conn,
5158 req,
5159 overwrite,
5160 NULL, /* src_dirfsp */
5161 fsp->fsp_name,
5162 dst_dirfsp, /* dst_dirfsp */
5163 smb_fname_dst);
5165 TALLOC_FREE(smb_fname_dst);
5166 return status;
5169 /****************************************************************************
5170 Deal with SMB_FILE_RENAME_INFORMATION.
5171 ****************************************************************************/
5173 static NTSTATUS smb_file_rename_information(connection_struct *conn,
5174 struct smb_request *req,
5175 const char *pdata,
5176 int total_data,
5177 files_struct *fsp,
5178 struct smb_filename *smb_fname_src)
5180 bool overwrite;
5181 uint32_t root_fid;
5182 uint32_t len;
5183 char *newname = NULL;
5184 struct files_struct *dst_dirfsp = NULL;
5185 struct smb_filename *smb_fname_dst = NULL;
5186 const char *dst_original_lcomp = NULL;
5187 NTSTATUS status = NT_STATUS_OK;
5188 char *p;
5189 TALLOC_CTX *ctx = talloc_tos();
5191 if (total_data < 13) {
5192 return NT_STATUS_INVALID_PARAMETER;
5195 overwrite = (CVAL(pdata,0) != 0);
5196 root_fid = IVAL(pdata,4);
5197 len = IVAL(pdata,8);
5199 if (len > (total_data - 12) || (len == 0) || (root_fid != 0)) {
5200 return NT_STATUS_INVALID_PARAMETER;
5203 if (req->posix_pathnames) {
5204 srvstr_get_path_posix(ctx,
5205 pdata,
5206 req->flags2,
5207 &newname,
5208 &pdata[12],
5209 len,
5211 &status);
5212 } else {
5213 srvstr_get_path(ctx,
5214 pdata,
5215 req->flags2,
5216 &newname,
5217 &pdata[12],
5218 len,
5220 &status);
5222 if (!NT_STATUS_IS_OK(status)) {
5223 return status;
5226 DEBUG(10,("smb_file_rename_information: got name |%s|\n",
5227 newname));
5229 /* Check the new name has no '/' characters. */
5230 if (strchr_m(newname, '/')) {
5231 return NT_STATUS_NOT_SUPPORTED;
5234 if (fsp && fsp->base_fsp) {
5235 /* newname must be a stream name. */
5236 if (newname[0] != ':') {
5237 return NT_STATUS_NOT_SUPPORTED;
5240 /* Create an smb_fname to call rename_internals_fsp() with. */
5241 smb_fname_dst = synthetic_smb_fname(talloc_tos(),
5242 fsp->base_fsp->fsp_name->base_name,
5243 newname,
5244 NULL,
5245 fsp->base_fsp->fsp_name->twrp,
5246 fsp->base_fsp->fsp_name->flags);
5247 if (smb_fname_dst == NULL) {
5248 status = NT_STATUS_NO_MEMORY;
5249 goto out;
5253 * Get the original last component, since
5254 * rename_internals_fsp() requires it.
5256 dst_original_lcomp = get_original_lcomp(smb_fname_dst,
5257 conn,
5258 newname,
5260 if (dst_original_lcomp == NULL) {
5261 status = NT_STATUS_NO_MEMORY;
5262 goto out;
5265 } else {
5267 * Build up an smb_fname_dst based on the filename passed in.
5268 * We basically just strip off the last component, and put on
5269 * the newname instead.
5271 char *base_name = NULL;
5272 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
5273 NTTIME dst_twrp = 0;
5275 /* newname must *not* be a stream name. */
5276 if (newname[0] == ':') {
5277 return NT_STATUS_NOT_SUPPORTED;
5281 * Strip off the last component (filename) of the path passed
5282 * in.
5284 base_name = talloc_strdup(ctx, smb_fname_src->base_name);
5285 if (!base_name) {
5286 return NT_STATUS_NO_MEMORY;
5288 p = strrchr_m(base_name, '/');
5289 if (p) {
5290 p[1] = '\0';
5291 } else {
5292 base_name = talloc_strdup(ctx, "");
5293 if (!base_name) {
5294 return NT_STATUS_NO_MEMORY;
5297 /* Append the new name. */
5298 base_name = talloc_asprintf_append(base_name,
5299 "%s",
5300 newname);
5301 if (!base_name) {
5302 return NT_STATUS_NO_MEMORY;
5305 if (ucf_flags & UCF_GMT_PATHNAME) {
5306 extract_snapshot_token(base_name, &dst_twrp);
5308 status = filename_convert_dirfsp(ctx,
5309 conn,
5310 base_name,
5311 ucf_flags,
5312 dst_twrp,
5313 &dst_dirfsp,
5314 &smb_fname_dst);
5316 if (!NT_STATUS_IS_OK(status)) {
5317 goto out;
5319 dst_original_lcomp = get_original_lcomp(smb_fname_dst,
5320 conn,
5321 newname,
5322 ucf_flags);
5323 if (dst_original_lcomp == NULL) {
5324 status = NT_STATUS_NO_MEMORY;
5325 goto out;
5329 if (fsp != NULL && fsp->fsp_flags.is_fsa) {
5330 DEBUG(10,("smb_file_rename_information: "
5331 "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
5332 fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
5333 smb_fname_str_dbg(smb_fname_dst)));
5334 status = rename_internals_fsp(conn,
5335 fsp,
5336 dst_dirfsp,
5337 smb_fname_dst,
5338 dst_original_lcomp,
5340 overwrite);
5341 } else {
5342 DEBUG(10,("smb_file_rename_information: "
5343 "SMB_FILE_RENAME_INFORMATION %s -> %s\n",
5344 smb_fname_str_dbg(smb_fname_src),
5345 smb_fname_str_dbg(smb_fname_dst)));
5346 status = rename_internals(ctx,
5347 conn,
5348 req,
5349 NULL, /* src_dirfsp */
5350 smb_fname_src,
5351 dst_dirfsp,
5352 smb_fname_dst,
5353 dst_original_lcomp,
5355 overwrite,
5356 FILE_WRITE_ATTRIBUTES);
5358 out:
5359 TALLOC_FREE(smb_fname_dst);
5360 return status;
5363 /****************************************************************************
5364 Deal with SMB_SET_POSIX_ACL.
5365 ****************************************************************************/
5367 #if defined(HAVE_POSIX_ACLS)
5368 static NTSTATUS smb_set_posix_acl(connection_struct *conn,
5369 struct smb_request *req,
5370 const char *pdata,
5371 int total_data_in,
5372 files_struct *fsp,
5373 struct smb_filename *smb_fname)
5375 uint16_t posix_acl_version;
5376 uint16_t num_file_acls;
5377 uint16_t num_def_acls;
5378 bool valid_file_acls = true;
5379 bool valid_def_acls = true;
5380 NTSTATUS status;
5381 unsigned int size_needed;
5382 unsigned int total_data;
5383 bool close_fsp = false;
5385 if (total_data_in < 0) {
5386 status = NT_STATUS_INVALID_PARAMETER;
5387 goto out;
5390 total_data = total_data_in;
5392 if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
5393 status = NT_STATUS_INVALID_PARAMETER;
5394 goto out;
5396 posix_acl_version = SVAL(pdata,0);
5397 num_file_acls = SVAL(pdata,2);
5398 num_def_acls = SVAL(pdata,4);
5400 if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
5401 valid_file_acls = false;
5402 num_file_acls = 0;
5405 if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
5406 valid_def_acls = false;
5407 num_def_acls = 0;
5410 if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
5411 status = NT_STATUS_INVALID_PARAMETER;
5412 goto out;
5415 /* Wrap checks. */
5416 if (num_file_acls + num_def_acls < num_file_acls) {
5417 status = NT_STATUS_INVALID_PARAMETER;
5418 goto out;
5421 size_needed = num_file_acls + num_def_acls;
5424 * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
5425 * than UINT_MAX, so check by division.
5427 if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
5428 status = NT_STATUS_INVALID_PARAMETER;
5429 goto out;
5432 size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
5433 if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
5434 status = NT_STATUS_INVALID_PARAMETER;
5435 goto out;
5437 size_needed += SMB_POSIX_ACL_HEADER_SIZE;
5439 if (total_data < size_needed) {
5440 status = NT_STATUS_INVALID_PARAMETER;
5441 goto out;
5445 * Ensure we always operate on a file descriptor, not just
5446 * the filename.
5448 if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
5449 uint32_t access_mask = SEC_STD_WRITE_OWNER|
5450 SEC_STD_WRITE_DAC|
5451 SEC_STD_READ_CONTROL|
5452 FILE_READ_ATTRIBUTES|
5453 FILE_WRITE_ATTRIBUTES;
5455 status = get_posix_fsp(conn,
5456 req,
5457 smb_fname,
5458 access_mask,
5459 &fsp);
5461 if (!NT_STATUS_IS_OK(status)) {
5462 goto out;
5464 close_fsp = true;
5467 /* Here we know fsp != NULL */
5468 SMB_ASSERT(fsp != NULL);
5470 status = refuse_symlink_fsp(fsp);
5471 if (!NT_STATUS_IS_OK(status)) {
5472 goto out;
5475 /* If we have a default acl, this *must* be a directory. */
5476 if (valid_def_acls && !fsp->fsp_flags.is_directory) {
5477 DBG_INFO("Can't set default acls on "
5478 "non-directory %s\n",
5479 fsp_str_dbg(fsp));
5480 return NT_STATUS_INVALID_HANDLE;
5483 DBG_DEBUG("file %s num_file_acls = %"PRIu16", "
5484 "num_def_acls = %"PRIu16"\n",
5485 fsp_str_dbg(fsp),
5486 num_file_acls,
5487 num_def_acls);
5489 /* Move pdata to the start of the file ACL entries. */
5490 pdata += SMB_POSIX_ACL_HEADER_SIZE;
5492 if (valid_file_acls) {
5493 status = set_unix_posix_acl(conn,
5494 fsp,
5495 num_file_acls,
5496 pdata);
5497 if (!NT_STATUS_IS_OK(status)) {
5498 goto out;
5502 /* Move pdata to the start of the default ACL entries. */
5503 pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
5505 if (valid_def_acls) {
5506 status = set_unix_posix_default_acl(conn,
5507 fsp,
5508 num_def_acls,
5509 pdata);
5510 if (!NT_STATUS_IS_OK(status)) {
5511 goto out;
5515 status = NT_STATUS_OK;
5517 out:
5519 if (close_fsp) {
5520 (void)close_file_free(req, &fsp, NORMAL_CLOSE);
5522 return status;
5524 #endif
5526 /****************************************************************************
5527 Deal with SMB_SET_FILE_BASIC_INFO.
5528 ****************************************************************************/
5530 static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
5531 const char *pdata,
5532 int total_data,
5533 files_struct *fsp,
5534 struct smb_filename *smb_fname)
5536 /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
5537 struct smb_file_time ft;
5538 uint32_t dosmode = 0;
5539 NTSTATUS status = NT_STATUS_OK;
5541 init_smb_file_time(&ft);
5543 if (total_data < 36) {
5544 return NT_STATUS_INVALID_PARAMETER;
5547 if (fsp == NULL) {
5548 return NT_STATUS_INVALID_HANDLE;
5551 status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES);
5552 if (!NT_STATUS_IS_OK(status)) {
5553 return status;
5556 /* Set the attributes */
5557 dosmode = IVAL(pdata,32);
5558 status = smb_set_file_dosmode(conn, fsp, dosmode);
5559 if (!NT_STATUS_IS_OK(status)) {
5560 return status;
5563 /* create time */
5564 ft.create_time = pull_long_date_full_timespec(pdata);
5566 /* access time */
5567 ft.atime = pull_long_date_full_timespec(pdata+8);
5569 /* write time. */
5570 ft.mtime = pull_long_date_full_timespec(pdata+16);
5572 /* change time. */
5573 ft.ctime = pull_long_date_full_timespec(pdata+24);
5575 DEBUG(10, ("smb_set_file_basic_info: file %s\n",
5576 smb_fname_str_dbg(smb_fname)));
5578 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
5579 if (!NT_STATUS_IS_OK(status)) {
5580 return status;
5583 if (fsp->fsp_flags.modified) {
5584 trigger_write_time_update_immediate(fsp);
5586 return NT_STATUS_OK;
5589 /****************************************************************************
5590 Deal with SMB_INFO_STANDARD.
5591 ****************************************************************************/
5593 static NTSTATUS smb_set_info_standard(connection_struct *conn,
5594 const char *pdata,
5595 int total_data,
5596 files_struct *fsp,
5597 struct smb_filename *smb_fname)
5599 NTSTATUS status;
5600 struct smb_file_time ft;
5602 init_smb_file_time(&ft);
5604 if (total_data < 12) {
5605 return NT_STATUS_INVALID_PARAMETER;
5608 if (fsp == NULL) {
5609 return NT_STATUS_INVALID_HANDLE;
5612 /* create time */
5613 ft.create_time = time_t_to_full_timespec(srv_make_unix_date2(pdata));
5614 /* access time */
5615 ft.atime = time_t_to_full_timespec(srv_make_unix_date2(pdata+4));
5616 /* write time */
5617 ft.mtime = time_t_to_full_timespec(srv_make_unix_date2(pdata+8));
5619 DEBUG(10,("smb_set_info_standard: file %s\n",
5620 smb_fname_str_dbg(smb_fname)));
5622 status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES);
5623 if (!NT_STATUS_IS_OK(status)) {
5624 return status;
5627 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
5628 if (!NT_STATUS_IS_OK(status)) {
5629 return status;
5632 if (fsp->fsp_flags.modified) {
5633 trigger_write_time_update_immediate(fsp);
5635 return NT_STATUS_OK;
5638 /****************************************************************************
5639 Deal with SMB_SET_FILE_ALLOCATION_INFO.
5640 ****************************************************************************/
5642 static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
5643 struct smb_request *req,
5644 const char *pdata,
5645 int total_data,
5646 files_struct *fsp,
5647 struct smb_filename *smb_fname)
5649 uint64_t allocation_size = 0;
5650 NTSTATUS status = NT_STATUS_OK;
5651 files_struct *new_fsp = NULL;
5653 if (!VALID_STAT(smb_fname->st)) {
5654 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5657 if (total_data < 8) {
5658 return NT_STATUS_INVALID_PARAMETER;
5661 allocation_size = (uint64_t)IVAL(pdata,0);
5662 allocation_size |= (((uint64_t)IVAL(pdata,4)) << 32);
5663 DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for "
5664 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
5665 (double)allocation_size));
5667 if (allocation_size) {
5668 allocation_size = smb_roundup(conn, allocation_size);
5671 DEBUG(10,("smb_set_file_allocation_info: file %s : setting new "
5672 "allocation size to %.0f\n", smb_fname_str_dbg(smb_fname),
5673 (double)allocation_size));
5675 if (fsp &&
5676 !fsp->fsp_flags.is_pathref &&
5677 fsp_get_io_fd(fsp) != -1)
5679 /* Open file handle. */
5680 if (!(fsp->access_mask & FILE_WRITE_DATA)) {
5681 return NT_STATUS_ACCESS_DENIED;
5684 /* Only change if needed. */
5685 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
5686 if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
5687 return map_nt_error_from_unix(errno);
5690 /* But always update the time. */
5692 * This is equivalent to a write. Ensure it's seen immediately
5693 * if there are no pending writes.
5695 trigger_write_time_update_immediate(fsp);
5696 return NT_STATUS_OK;
5699 /* Pathname or stat or directory file. */
5700 status = SMB_VFS_CREATE_FILE(
5701 conn, /* conn */
5702 req, /* req */
5703 NULL, /* dirfsp */
5704 smb_fname, /* fname */
5705 FILE_WRITE_DATA, /* access_mask */
5706 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5707 FILE_SHARE_DELETE),
5708 FILE_OPEN, /* create_disposition*/
5709 0, /* create_options */
5710 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
5711 0, /* oplock_request */
5712 NULL, /* lease */
5713 0, /* allocation_size */
5714 0, /* private_flags */
5715 NULL, /* sd */
5716 NULL, /* ea_list */
5717 &new_fsp, /* result */
5718 NULL, /* pinfo */
5719 NULL, NULL); /* create context */
5721 if (!NT_STATUS_IS_OK(status)) {
5722 /* NB. We check for open_was_deferred in the caller. */
5723 return status;
5726 /* Only change if needed. */
5727 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
5728 if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) {
5729 status = map_nt_error_from_unix(errno);
5730 close_file_free(req, &new_fsp, NORMAL_CLOSE);
5731 return status;
5735 /* Changing the allocation size should set the last mod time. */
5737 * This is equivalent to a write. Ensure it's seen immediately
5738 * if there are no pending writes.
5740 trigger_write_time_update_immediate(new_fsp);
5741 close_file_free(req, &new_fsp, NORMAL_CLOSE);
5742 return NT_STATUS_OK;
5745 /****************************************************************************
5746 Deal with SMB_SET_FILE_END_OF_FILE_INFO.
5747 ****************************************************************************/
5749 static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
5750 struct smb_request *req,
5751 const char *pdata,
5752 int total_data,
5753 files_struct *fsp,
5754 struct smb_filename *smb_fname,
5755 bool fail_after_createfile)
5757 off_t size;
5759 if (total_data < 8) {
5760 return NT_STATUS_INVALID_PARAMETER;
5763 size = IVAL(pdata,0);
5764 size |= (((off_t)IVAL(pdata,4)) << 32);
5765 DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for "
5766 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
5767 (double)size));
5769 return smb_set_file_size(conn, req,
5770 fsp,
5771 smb_fname,
5772 &smb_fname->st,
5773 size,
5774 fail_after_createfile);
5777 /****************************************************************************
5778 Allow a UNIX info mknod.
5779 ****************************************************************************/
5781 static NTSTATUS smb_unix_mknod(connection_struct *conn,
5782 const char *pdata,
5783 int total_data,
5784 const struct smb_filename *smb_fname)
5786 uint32_t file_type = IVAL(pdata,56);
5787 #if defined(HAVE_MAKEDEV)
5788 uint32_t dev_major = IVAL(pdata,60);
5789 uint32_t dev_minor = IVAL(pdata,68);
5790 #endif
5791 SMB_DEV_T dev = (SMB_DEV_T)0;
5792 uint32_t raw_unixmode = IVAL(pdata,84);
5793 NTSTATUS status;
5794 mode_t unixmode;
5795 int ret;
5796 struct smb_filename *parent_fname = NULL;
5797 struct smb_filename *base_name = NULL;
5799 if (total_data < 100) {
5800 return NT_STATUS_INVALID_PARAMETER;
5803 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
5804 PERM_NEW_FILE, &unixmode);
5805 if (!NT_STATUS_IS_OK(status)) {
5806 return status;
5809 #if defined(HAVE_MAKEDEV)
5810 dev = makedev(dev_major, dev_minor);
5811 #endif
5813 switch (file_type) {
5814 /* We can't create other objects here. */
5815 case UNIX_TYPE_FILE:
5816 case UNIX_TYPE_DIR:
5817 case UNIX_TYPE_SYMLINK:
5818 return NT_STATUS_ACCESS_DENIED;
5819 #if defined(S_IFIFO)
5820 case UNIX_TYPE_FIFO:
5821 unixmode |= S_IFIFO;
5822 break;
5823 #endif
5824 #if defined(S_IFSOCK)
5825 case UNIX_TYPE_SOCKET:
5826 unixmode |= S_IFSOCK;
5827 break;
5828 #endif
5829 #if defined(S_IFCHR)
5830 case UNIX_TYPE_CHARDEV:
5831 /* This is only allowed for root. */
5832 if (get_current_uid(conn) != sec_initial_uid()) {
5833 return NT_STATUS_ACCESS_DENIED;
5835 unixmode |= S_IFCHR;
5836 break;
5837 #endif
5838 #if defined(S_IFBLK)
5839 case UNIX_TYPE_BLKDEV:
5840 if (get_current_uid(conn) != sec_initial_uid()) {
5841 return NT_STATUS_ACCESS_DENIED;
5843 unixmode |= S_IFBLK;
5844 break;
5845 #endif
5846 default:
5847 return NT_STATUS_INVALID_PARAMETER;
5850 DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
5851 "%.0f mode 0%o for file %s\n", (double)dev,
5852 (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
5854 status = parent_pathref(talloc_tos(),
5855 conn->cwd_fsp,
5856 smb_fname,
5857 &parent_fname,
5858 &base_name);
5859 if (!NT_STATUS_IS_OK(status)) {
5860 return status;
5863 /* Ok - do the mknod. */
5864 ret = SMB_VFS_MKNODAT(conn,
5865 parent_fname->fsp,
5866 base_name,
5867 unixmode,
5868 dev);
5870 if (ret != 0) {
5871 TALLOC_FREE(parent_fname);
5872 return map_nt_error_from_unix(errno);
5875 /* If any of the other "set" calls fail we
5876 * don't want to end up with a half-constructed mknod.
5879 if (lp_inherit_permissions(SNUM(conn))) {
5880 inherit_access_posix_acl(conn,
5881 parent_fname->fsp,
5882 smb_fname,
5883 unixmode);
5885 TALLOC_FREE(parent_fname);
5887 return NT_STATUS_OK;
5890 /****************************************************************************
5891 Deal with SMB_SET_FILE_UNIX_BASIC.
5892 ****************************************************************************/
5894 static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
5895 struct smb_request *req,
5896 const char *pdata,
5897 int total_data,
5898 files_struct *fsp,
5899 struct smb_filename *smb_fname)
5901 struct smb_file_time ft;
5902 uint32_t raw_unixmode;
5903 mode_t unixmode;
5904 off_t size = 0;
5905 uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
5906 gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
5907 NTSTATUS status = NT_STATUS_OK;
5908 enum perm_type ptype;
5909 files_struct *all_fsps = NULL;
5910 bool modify_mtime = true;
5911 struct file_id id;
5912 SMB_STRUCT_STAT sbuf;
5914 init_smb_file_time(&ft);
5916 if (total_data < 100) {
5917 return NT_STATUS_INVALID_PARAMETER;
5920 if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
5921 IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
5922 size=IVAL(pdata,0); /* first 8 Bytes are size */
5923 size |= (((off_t)IVAL(pdata,4)) << 32);
5926 ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
5927 ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
5928 set_owner = (uid_t)IVAL(pdata,40);
5929 set_grp = (gid_t)IVAL(pdata,48);
5930 raw_unixmode = IVAL(pdata,84);
5932 if (VALID_STAT(smb_fname->st)) {
5933 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
5934 ptype = PERM_EXISTING_DIR;
5935 } else {
5936 ptype = PERM_EXISTING_FILE;
5938 } else {
5939 ptype = PERM_NEW_FILE;
5942 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
5943 ptype, &unixmode);
5944 if (!NT_STATUS_IS_OK(status)) {
5945 return status;
5948 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
5949 "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
5950 smb_fname_str_dbg(smb_fname), (double)size,
5951 (unsigned int)set_owner, (unsigned int)set_grp,
5952 (int)raw_unixmode));
5954 sbuf = smb_fname->st;
5956 if (!VALID_STAT(sbuf)) {
5958 * The only valid use of this is to create character and block
5959 * devices, and named pipes. This is deprecated (IMHO) and
5960 * a new info level should be used for mknod. JRA.
5963 return smb_unix_mknod(conn,
5964 pdata,
5965 total_data,
5966 smb_fname);
5969 #if 1
5970 /* Horrible backwards compatibility hack as an old server bug
5971 * allowed a CIFS client bug to remain unnoticed :-(. JRA.
5972 * */
5974 if (!size) {
5975 size = get_file_size_stat(&sbuf);
5977 #endif
5980 * Deal with the UNIX specific mode set.
5983 if (raw_unixmode != SMB_MODE_NO_CHANGE) {
5984 int ret;
5986 if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
5987 DBG_WARNING("Can't set mode on symlink %s\n",
5988 smb_fname_str_dbg(smb_fname));
5989 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5992 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
5993 "setting mode 0%o for file %s\n",
5994 (unsigned int)unixmode,
5995 smb_fname_str_dbg(smb_fname)));
5996 ret = SMB_VFS_FCHMOD(fsp, unixmode);
5997 if (ret != 0) {
5998 return map_nt_error_from_unix(errno);
6003 * Deal with the UNIX specific uid set.
6006 if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
6007 (sbuf.st_ex_uid != set_owner)) {
6008 int ret;
6010 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6011 "changing owner %u for path %s\n",
6012 (unsigned int)set_owner,
6013 smb_fname_str_dbg(smb_fname)));
6015 if (fsp &&
6016 !fsp->fsp_flags.is_pathref &&
6017 fsp_get_io_fd(fsp) != -1)
6019 ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
6020 } else {
6022 * UNIX extensions calls must always operate
6023 * on symlinks.
6025 ret = SMB_VFS_LCHOWN(conn, smb_fname,
6026 set_owner, (gid_t)-1);
6029 if (ret != 0) {
6030 status = map_nt_error_from_unix(errno);
6031 return status;
6036 * Deal with the UNIX specific gid set.
6039 if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
6040 (sbuf.st_ex_gid != set_grp)) {
6041 int ret;
6043 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6044 "changing group %u for file %s\n",
6045 (unsigned int)set_grp,
6046 smb_fname_str_dbg(smb_fname)));
6047 if (fsp &&
6048 !fsp->fsp_flags.is_pathref &&
6049 fsp_get_io_fd(fsp) != -1)
6051 ret = SMB_VFS_FCHOWN(fsp, (uid_t)-1, set_grp);
6052 } else {
6054 * UNIX extensions calls must always operate
6055 * on symlinks.
6057 ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
6058 set_grp);
6060 if (ret != 0) {
6061 status = map_nt_error_from_unix(errno);
6062 return status;
6066 /* Deal with any size changes. */
6068 if (S_ISREG(sbuf.st_ex_mode)) {
6069 status = smb_set_file_size(conn, req,
6070 fsp,
6071 smb_fname,
6072 &sbuf,
6073 size,
6074 false);
6075 if (!NT_STATUS_IS_OK(status)) {
6076 return status;
6080 /* Deal with any time changes. */
6081 if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
6082 /* No change, don't cancel anything. */
6083 return status;
6086 id = vfs_file_id_from_sbuf(conn, &sbuf);
6087 for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
6088 all_fsps = file_find_di_next(all_fsps, true)) {
6090 * We're setting the time explicitly for UNIX.
6091 * Cancel any pending changes over all handles.
6093 all_fsps->fsp_flags.update_write_time_on_close = false;
6094 TALLOC_FREE(all_fsps->update_write_time_event);
6098 * Override the "setting_write_time"
6099 * parameter here as it almost does what
6100 * we need. Just remember if we modified
6101 * mtime and send the notify ourselves.
6103 if (is_omit_timespec(&ft.mtime)) {
6104 modify_mtime = false;
6107 status = smb_set_file_time(conn,
6108 fsp,
6109 smb_fname,
6110 &ft,
6111 false);
6112 if (modify_mtime) {
6113 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6114 FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
6116 return status;
6119 /****************************************************************************
6120 Deal with SMB_SET_FILE_UNIX_INFO2.
6121 ****************************************************************************/
6123 static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
6124 struct smb_request *req,
6125 const char *pdata,
6126 int total_data,
6127 files_struct *fsp,
6128 struct smb_filename *smb_fname)
6130 NTSTATUS status;
6131 uint32_t smb_fflags;
6132 uint32_t smb_fmask;
6134 if (total_data < 116) {
6135 return NT_STATUS_INVALID_PARAMETER;
6138 /* Start by setting all the fields that are common between UNIX_BASIC
6139 * and UNIX_INFO2.
6141 status = smb_set_file_unix_basic(conn, req, pdata, total_data,
6142 fsp, smb_fname);
6143 if (!NT_STATUS_IS_OK(status)) {
6144 return status;
6147 smb_fflags = IVAL(pdata, 108);
6148 smb_fmask = IVAL(pdata, 112);
6150 /* NB: We should only attempt to alter the file flags if the client
6151 * sends a non-zero mask.
6153 if (smb_fmask != 0) {
6154 int stat_fflags = 0;
6156 if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
6157 smb_fmask, &stat_fflags)) {
6158 /* Client asked to alter a flag we don't understand. */
6159 return NT_STATUS_INVALID_PARAMETER;
6162 if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
6163 DBG_WARNING("Can't change flags on symlink %s\n",
6164 smb_fname_str_dbg(smb_fname));
6165 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6167 if (SMB_VFS_FCHFLAGS(fsp, stat_fflags) != 0) {
6168 return map_nt_error_from_unix(errno);
6172 /* XXX: need to add support for changing the create_time here. You
6173 * can do this for paths on Darwin with setattrlist(2). The right way
6174 * to hook this up is probably by extending the VFS utimes interface.
6177 return NT_STATUS_OK;
6180 /****************************************************************************
6181 Create a directory with POSIX semantics.
6182 ****************************************************************************/
6184 static NTSTATUS smb_posix_mkdir(connection_struct *conn,
6185 struct smb_request *req,
6186 char **ppdata,
6187 int total_data,
6188 struct smb_filename *smb_fname,
6189 int *pdata_return_size)
6191 NTSTATUS status = NT_STATUS_OK;
6192 uint32_t raw_unixmode = 0;
6193 mode_t unixmode = (mode_t)0;
6194 files_struct *fsp = NULL;
6195 uint16_t info_level_return = 0;
6196 int info;
6197 char *pdata = *ppdata;
6198 struct smb2_create_blobs *posx = NULL;
6200 if (total_data < 18) {
6201 return NT_STATUS_INVALID_PARAMETER;
6204 raw_unixmode = IVAL(pdata,8);
6205 /* Next 4 bytes are not yet defined. */
6207 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6208 PERM_NEW_DIR, &unixmode);
6209 if (!NT_STATUS_IS_OK(status)) {
6210 return status;
6213 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
6214 if (!NT_STATUS_IS_OK(status)) {
6215 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
6216 nt_errstr(status));
6217 return status;
6220 DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
6221 smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
6223 status = SMB_VFS_CREATE_FILE(
6224 conn, /* conn */
6225 req, /* req */
6226 NULL, /* dirfsp */
6227 smb_fname, /* fname */
6228 FILE_READ_ATTRIBUTES, /* access_mask */
6229 FILE_SHARE_NONE, /* share_access */
6230 FILE_CREATE, /* create_disposition*/
6231 FILE_DIRECTORY_FILE, /* create_options */
6232 0, /* file_attributes */
6233 0, /* oplock_request */
6234 NULL, /* lease */
6235 0, /* allocation_size */
6236 0, /* private_flags */
6237 NULL, /* sd */
6238 NULL, /* ea_list */
6239 &fsp, /* result */
6240 &info, /* pinfo */
6241 posx, /* in_context_blobs */
6242 NULL); /* out_context_blobs */
6244 TALLOC_FREE(posx);
6246 if (NT_STATUS_IS_OK(status)) {
6247 close_file_free(req, &fsp, NORMAL_CLOSE);
6250 info_level_return = SVAL(pdata,16);
6252 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
6253 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
6254 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
6255 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
6256 } else {
6257 *pdata_return_size = 12;
6260 /* Realloc the data size */
6261 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
6262 if (*ppdata == NULL) {
6263 *pdata_return_size = 0;
6264 return NT_STATUS_NO_MEMORY;
6266 pdata = *ppdata;
6268 SSVAL(pdata,0,NO_OPLOCK_RETURN);
6269 SSVAL(pdata,2,0); /* No fnum. */
6270 SIVAL(pdata,4,info); /* Was directory created. */
6272 switch (info_level_return) {
6273 case SMB_QUERY_FILE_UNIX_BASIC:
6274 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
6275 SSVAL(pdata,10,0); /* Padding. */
6276 store_file_unix_basic(conn, pdata + 12, fsp,
6277 &smb_fname->st);
6278 break;
6279 case SMB_QUERY_FILE_UNIX_INFO2:
6280 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
6281 SSVAL(pdata,10,0); /* Padding. */
6282 store_file_unix_basic_info2(conn, pdata + 12, fsp,
6283 &smb_fname->st);
6284 break;
6285 default:
6286 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
6287 SSVAL(pdata,10,0); /* Padding. */
6288 break;
6291 return status;
6294 /****************************************************************************
6295 Open/Create a file with POSIX semantics.
6296 ****************************************************************************/
6298 #define SMB_O_RDONLY_MAPPING (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
6299 #define SMB_O_WRONLY_MAPPING (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA)
6301 static NTSTATUS smb_posix_open(connection_struct *conn,
6302 struct smb_request *req,
6303 char **ppdata,
6304 int total_data,
6305 struct smb_filename *smb_fname,
6306 int *pdata_return_size)
6308 bool extended_oplock_granted = False;
6309 char *pdata = *ppdata;
6310 uint32_t flags = 0;
6311 uint32_t wire_open_mode = 0;
6312 uint32_t raw_unixmode = 0;
6313 uint32_t attributes = 0;
6314 uint32_t create_disp = 0;
6315 uint32_t access_mask = 0;
6316 uint32_t create_options = FILE_NON_DIRECTORY_FILE;
6317 NTSTATUS status = NT_STATUS_OK;
6318 mode_t unixmode = (mode_t)0;
6319 files_struct *fsp = NULL;
6320 int oplock_request = 0;
6321 int info = 0;
6322 uint16_t info_level_return = 0;
6323 struct smb2_create_blobs *posx = NULL;
6325 if (total_data < 18) {
6326 return NT_STATUS_INVALID_PARAMETER;
6329 flags = IVAL(pdata,0);
6330 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
6331 if (oplock_request) {
6332 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
6335 wire_open_mode = IVAL(pdata,4);
6337 if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
6338 return smb_posix_mkdir(conn, req,
6339 ppdata,
6340 total_data,
6341 smb_fname,
6342 pdata_return_size);
6345 switch (wire_open_mode & SMB_ACCMODE) {
6346 case SMB_O_RDONLY:
6347 access_mask = SMB_O_RDONLY_MAPPING;
6348 break;
6349 case SMB_O_WRONLY:
6350 access_mask = SMB_O_WRONLY_MAPPING;
6351 break;
6352 case SMB_O_RDWR:
6353 access_mask = (SMB_O_RDONLY_MAPPING|
6354 SMB_O_WRONLY_MAPPING);
6355 break;
6356 default:
6357 DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
6358 (unsigned int)wire_open_mode ));
6359 return NT_STATUS_INVALID_PARAMETER;
6362 wire_open_mode &= ~SMB_ACCMODE;
6364 /* First take care of O_CREAT|O_EXCL interactions. */
6365 switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
6366 case (SMB_O_CREAT | SMB_O_EXCL):
6367 /* File exists fail. File not exist create. */
6368 create_disp = FILE_CREATE;
6369 break;
6370 case SMB_O_CREAT:
6371 /* File exists open. File not exist create. */
6372 create_disp = FILE_OPEN_IF;
6373 break;
6374 case SMB_O_EXCL:
6375 /* O_EXCL on its own without O_CREAT is undefined.
6376 We deliberately ignore it as some versions of
6377 Linux CIFSFS can send a bare O_EXCL on the
6378 wire which other filesystems in the kernel
6379 ignore. See bug 9519 for details. */
6381 /* Fallthrough. */
6383 case 0:
6384 /* File exists open. File not exist fail. */
6385 create_disp = FILE_OPEN;
6386 break;
6387 default:
6388 DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
6389 (unsigned int)wire_open_mode ));
6390 return NT_STATUS_INVALID_PARAMETER;
6393 /* Next factor in the effects of O_TRUNC. */
6394 wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);
6396 if (wire_open_mode & SMB_O_TRUNC) {
6397 switch (create_disp) {
6398 case FILE_CREATE:
6399 /* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
6400 /* Leave create_disp alone as
6401 (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
6403 /* File exists fail. File not exist create. */
6404 break;
6405 case FILE_OPEN_IF:
6406 /* SMB_O_CREAT | SMB_O_TRUNC */
6407 /* File exists overwrite. File not exist create. */
6408 create_disp = FILE_OVERWRITE_IF;
6409 break;
6410 case FILE_OPEN:
6411 /* SMB_O_TRUNC */
6412 /* File exists overwrite. File not exist fail. */
6413 create_disp = FILE_OVERWRITE;
6414 break;
6415 default:
6416 /* Cannot get here. */
6417 smb_panic("smb_posix_open: logic error");
6418 return NT_STATUS_INVALID_PARAMETER;
6422 raw_unixmode = IVAL(pdata,8);
6423 /* Next 4 bytes are not yet defined. */
6425 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6426 (VALID_STAT(smb_fname->st) ?
6427 PERM_EXISTING_FILE : PERM_NEW_FILE),
6428 &unixmode);
6430 if (!NT_STATUS_IS_OK(status)) {
6431 return status;
6434 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
6435 if (!NT_STATUS_IS_OK(status)) {
6436 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
6437 nt_errstr(status));
6438 return status;
6441 if (wire_open_mode & SMB_O_SYNC) {
6442 create_options |= FILE_WRITE_THROUGH;
6444 if (wire_open_mode & SMB_O_APPEND) {
6445 access_mask |= FILE_APPEND_DATA;
6447 if (wire_open_mode & SMB_O_DIRECT) {
6448 attributes |= FILE_FLAG_NO_BUFFERING;
6451 if ((wire_open_mode & SMB_O_DIRECTORY) ||
6452 VALID_STAT_OF_DIR(smb_fname->st)) {
6453 if (access_mask != SMB_O_RDONLY_MAPPING) {
6454 return NT_STATUS_FILE_IS_A_DIRECTORY;
6456 create_options &= ~FILE_NON_DIRECTORY_FILE;
6457 create_options |= FILE_DIRECTORY_FILE;
6460 DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
6461 smb_fname_str_dbg(smb_fname),
6462 (unsigned int)wire_open_mode,
6463 (unsigned int)unixmode ));
6465 status = SMB_VFS_CREATE_FILE(
6466 conn, /* conn */
6467 req, /* req */
6468 NULL, /* dirfsp */
6469 smb_fname, /* fname */
6470 access_mask, /* access_mask */
6471 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6472 FILE_SHARE_DELETE),
6473 create_disp, /* create_disposition*/
6474 create_options, /* create_options */
6475 attributes, /* file_attributes */
6476 oplock_request, /* oplock_request */
6477 NULL, /* lease */
6478 0, /* allocation_size */
6479 0, /* private_flags */
6480 NULL, /* sd */
6481 NULL, /* ea_list */
6482 &fsp, /* result */
6483 &info, /* pinfo */
6484 posx, /* in_context_blobs */
6485 NULL); /* out_context_blobs */
6487 TALLOC_FREE(posx);
6489 if (!NT_STATUS_IS_OK(status)) {
6490 return status;
6493 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
6494 extended_oplock_granted = True;
6497 if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
6498 extended_oplock_granted = True;
6501 info_level_return = SVAL(pdata,16);
6503 /* Allocate the correct return size. */
6505 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
6506 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
6507 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
6508 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
6509 } else {
6510 *pdata_return_size = 12;
6513 /* Realloc the data size */
6514 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
6515 if (*ppdata == NULL) {
6516 close_file_free(req, &fsp, ERROR_CLOSE);
6517 *pdata_return_size = 0;
6518 return NT_STATUS_NO_MEMORY;
6520 pdata = *ppdata;
6522 if (extended_oplock_granted) {
6523 if (flags & REQUEST_BATCH_OPLOCK) {
6524 SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
6525 } else {
6526 SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
6528 } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
6529 SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
6530 } else {
6531 SSVAL(pdata,0,NO_OPLOCK_RETURN);
6534 SSVAL(pdata,2,fsp->fnum);
6535 SIVAL(pdata,4,info); /* Was file created etc. */
6537 switch (info_level_return) {
6538 case SMB_QUERY_FILE_UNIX_BASIC:
6539 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
6540 SSVAL(pdata,10,0); /* padding. */
6541 store_file_unix_basic(conn, pdata + 12, fsp,
6542 &smb_fname->st);
6543 break;
6544 case SMB_QUERY_FILE_UNIX_INFO2:
6545 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
6546 SSVAL(pdata,10,0); /* padding. */
6547 store_file_unix_basic_info2(conn, pdata + 12, fsp,
6548 &smb_fname->st);
6549 break;
6550 default:
6551 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
6552 SSVAL(pdata,10,0); /* padding. */
6553 break;
6555 return NT_STATUS_OK;
6558 /****************************************************************************
6559 Delete a file with POSIX semantics.
6560 ****************************************************************************/
6562 struct smb_posix_unlink_state {
6563 struct smb_filename *smb_fname;
6564 struct files_struct *fsp;
6565 NTSTATUS status;
6568 static void smb_posix_unlink_locked(struct share_mode_lock *lck,
6569 void *private_data)
6571 struct smb_posix_unlink_state *state = private_data;
6572 char del = 1;
6573 bool other_nonposix_opens;
6575 other_nonposix_opens = has_other_nonposix_opens(lck, state->fsp);
6576 if (other_nonposix_opens) {
6577 /* Fail with sharing violation. */
6578 state->status = NT_STATUS_SHARING_VIOLATION;
6579 return;
6583 * Set the delete on close.
6585 state->status = smb_set_file_disposition_info(state->fsp->conn,
6586 &del,
6588 state->fsp,
6589 state->smb_fname);
6592 static NTSTATUS smb_posix_unlink(connection_struct *conn,
6593 struct smb_request *req,
6594 const char *pdata,
6595 int total_data,
6596 struct smb_filename *smb_fname)
6598 struct smb_posix_unlink_state state = {};
6599 NTSTATUS status = NT_STATUS_OK;
6600 files_struct *fsp = NULL;
6601 uint16_t flags = 0;
6602 int info = 0;
6603 int create_options = 0;
6604 struct smb2_create_blobs *posx = NULL;
6606 if (total_data < 2) {
6607 return NT_STATUS_INVALID_PARAMETER;
6610 flags = SVAL(pdata,0);
6612 if (!VALID_STAT(smb_fname->st)) {
6613 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6616 if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
6617 !VALID_STAT_OF_DIR(smb_fname->st)) {
6618 return NT_STATUS_NOT_A_DIRECTORY;
6621 DEBUG(10,("smb_posix_unlink: %s %s\n",
6622 (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
6623 smb_fname_str_dbg(smb_fname)));
6625 if (VALID_STAT_OF_DIR(smb_fname->st)) {
6626 create_options |= FILE_DIRECTORY_FILE;
6629 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
6630 if (!NT_STATUS_IS_OK(status)) {
6631 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
6632 nt_errstr(status));
6633 return status;
6636 status = SMB_VFS_CREATE_FILE(
6637 conn, /* conn */
6638 req, /* req */
6639 NULL, /* dirfsp */
6640 smb_fname, /* fname */
6641 DELETE_ACCESS, /* access_mask */
6642 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6643 FILE_SHARE_DELETE),
6644 FILE_OPEN, /* create_disposition*/
6645 create_options, /* create_options */
6646 0, /* file_attributes */
6647 0, /* oplock_request */
6648 NULL, /* lease */
6649 0, /* allocation_size */
6650 0, /* private_flags */
6651 NULL, /* sd */
6652 NULL, /* ea_list */
6653 &fsp, /* result */
6654 &info, /* pinfo */
6655 posx, /* in_context_blobs */
6656 NULL); /* out_context_blobs */
6658 TALLOC_FREE(posx);
6660 if (!NT_STATUS_IS_OK(status)) {
6661 return status;
6665 * Don't lie to client. If we can't really delete due to
6666 * non-POSIX opens return SHARING_VIOLATION.
6669 state = (struct smb_posix_unlink_state) {
6670 .smb_fname = smb_fname,
6671 .fsp = fsp,
6674 status = share_mode_do_locked_vfs_allowed(fsp->file_id,
6675 smb_posix_unlink_locked,
6676 &state);
6677 if (!NT_STATUS_IS_OK(status)) {
6678 DBG_ERR("share_mode_do_locked_vfs_allowed(%s) failed - %s\n",
6679 fsp_str_dbg(fsp), nt_errstr(status));
6680 close_file_free(req, &fsp, NORMAL_CLOSE);
6681 return NT_STATUS_INVALID_PARAMETER;
6684 status = state.status;
6685 if (!NT_STATUS_IS_OK(status)) {
6686 close_file_free(req, &fsp, NORMAL_CLOSE);
6687 return status;
6689 return close_file_free(req, &fsp, NORMAL_CLOSE);
6692 static NTSTATUS smbd_do_posix_setfilepathinfo(struct connection_struct *conn,
6693 struct smb_request *req,
6694 TALLOC_CTX *mem_ctx,
6695 uint16_t info_level,
6696 struct smb_filename *smb_fname,
6697 files_struct *fsp,
6698 char **ppdata,
6699 int total_data,
6700 int *ret_data_size)
6702 char *pdata = *ppdata;
6703 NTSTATUS status = NT_STATUS_OK;
6704 int data_return_size = 0;
6706 *ret_data_size = 0;
6708 if (!CAN_WRITE(conn)) {
6709 /* Allow POSIX opens. The open path will deny
6710 * any non-readonly opens. */
6711 if (info_level != SMB_POSIX_PATH_OPEN) {
6712 return NT_STATUS_DOS(ERRSRV, ERRaccess);
6716 DBG_DEBUG("file=%s (%s) info_level=%d totdata=%d\n",
6717 smb_fname_str_dbg(smb_fname),
6718 fsp_fnum_dbg(fsp),
6719 info_level,
6720 total_data);
6722 switch (info_level) {
6723 case SMB_SET_FILE_UNIX_BASIC:
6725 status = smb_set_file_unix_basic(conn, req,
6726 pdata,
6727 total_data,
6728 fsp,
6729 smb_fname);
6730 break;
6733 case SMB_SET_FILE_UNIX_INFO2:
6735 status = smb_set_file_unix_info2(conn, req,
6736 pdata,
6737 total_data,
6738 fsp,
6739 smb_fname);
6740 break;
6743 case SMB_SET_FILE_UNIX_LINK:
6745 if (smb_fname == NULL) {
6746 /* We must have a pathname for this. */
6747 return NT_STATUS_INVALID_LEVEL;
6749 status = smb_set_file_unix_link(conn, req, pdata,
6750 total_data, smb_fname);
6751 break;
6754 case SMB_SET_FILE_UNIX_HLINK:
6756 if (smb_fname == NULL) {
6757 /* We must have a pathname for this. */
6758 return NT_STATUS_INVALID_LEVEL;
6760 status = smb_set_file_unix_hlink(conn, req,
6761 pdata, total_data,
6762 smb_fname);
6763 break;
6766 #if defined(HAVE_POSIX_ACLS)
6767 case SMB_SET_POSIX_ACL:
6769 status = smb_set_posix_acl(conn,
6770 req,
6771 pdata,
6772 total_data,
6773 fsp,
6774 smb_fname);
6775 break;
6777 #endif
6779 #if defined(WITH_SMB1SERVER)
6780 case SMB_SET_POSIX_LOCK:
6782 if (fsp == NULL) {
6783 return NT_STATUS_INVALID_LEVEL;
6785 status = smb_set_posix_lock(conn, req,
6786 pdata, total_data, fsp);
6787 break;
6789 #endif
6791 case SMB_POSIX_PATH_OPEN:
6793 if (smb_fname == NULL) {
6794 /* We must have a pathname for this. */
6795 return NT_STATUS_INVALID_LEVEL;
6798 status = smb_posix_open(conn, req,
6799 ppdata,
6800 total_data,
6801 smb_fname,
6802 &data_return_size);
6803 break;
6806 case SMB_POSIX_PATH_UNLINK:
6808 if (smb_fname == NULL) {
6809 /* We must have a pathname for this. */
6810 return NT_STATUS_INVALID_LEVEL;
6813 status = smb_posix_unlink(conn, req,
6814 pdata,
6815 total_data,
6816 smb_fname);
6817 break;
6820 default:
6821 return NT_STATUS_INVALID_LEVEL;
6824 if (!NT_STATUS_IS_OK(status)) {
6825 return status;
6828 *ret_data_size = data_return_size;
6829 return NT_STATUS_OK;
6832 NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
6833 struct smb_request *req,
6834 TALLOC_CTX *mem_ctx,
6835 uint16_t info_level,
6836 files_struct *fsp,
6837 struct smb_filename *smb_fname,
6838 char **ppdata, int total_data,
6839 int *ret_data_size)
6841 char *pdata = *ppdata;
6842 NTSTATUS status = NT_STATUS_OK;
6843 int data_return_size = 0;
6845 if (INFO_LEVEL_IS_UNIX(info_level)) {
6846 if (!lp_smb1_unix_extensions()) {
6847 return NT_STATUS_INVALID_LEVEL;
6849 if (!req->posix_pathnames) {
6850 return NT_STATUS_INVALID_LEVEL;
6852 status = smbd_do_posix_setfilepathinfo(conn,
6853 req,
6854 req,
6855 info_level,
6856 smb_fname,
6857 fsp,
6858 ppdata,
6859 total_data,
6860 &data_return_size);
6861 if (!NT_STATUS_IS_OK(status)) {
6862 return status;
6864 *ret_data_size = data_return_size;
6865 return NT_STATUS_OK;
6868 *ret_data_size = 0;
6870 DEBUG(3,("smbd_do_setfilepathinfo: %s (%s) info_level=%d "
6871 "totdata=%d\n", smb_fname_str_dbg(smb_fname),
6872 fsp_fnum_dbg(fsp),
6873 info_level, total_data));
6875 switch (info_level) {
6877 case SMB_INFO_STANDARD:
6879 status = smb_set_info_standard(conn,
6880 pdata,
6881 total_data,
6882 fsp,
6883 smb_fname);
6884 break;
6887 case SMB_INFO_SET_EA:
6889 status = smb_info_set_ea(conn,
6890 pdata,
6891 total_data,
6892 fsp,
6893 smb_fname);
6894 break;
6897 case SMB_SET_FILE_BASIC_INFO:
6898 case SMB_FILE_BASIC_INFORMATION:
6900 status = smb_set_file_basic_info(conn,
6901 pdata,
6902 total_data,
6903 fsp,
6904 smb_fname);
6905 break;
6908 case SMB_FILE_ALLOCATION_INFORMATION:
6909 case SMB_SET_FILE_ALLOCATION_INFO:
6911 status = smb_set_file_allocation_info(conn, req,
6912 pdata,
6913 total_data,
6914 fsp,
6915 smb_fname);
6916 break;
6919 case SMB_FILE_END_OF_FILE_INFORMATION:
6920 case SMB_SET_FILE_END_OF_FILE_INFO:
6923 * XP/Win7 both fail after the createfile with
6924 * SMB_SET_FILE_END_OF_FILE_INFO but not
6925 * SMB_FILE_END_OF_FILE_INFORMATION (pass-through).
6926 * The level is known here, so pass it down
6927 * appropriately.
6929 bool should_fail =
6930 (info_level == SMB_SET_FILE_END_OF_FILE_INFO);
6932 status = smb_set_file_end_of_file_info(conn, req,
6933 pdata,
6934 total_data,
6935 fsp,
6936 smb_fname,
6937 should_fail);
6938 break;
6941 case SMB_FILE_DISPOSITION_INFORMATION:
6942 case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
6944 #if 0
6945 /* JRA - We used to just ignore this on a path ?
6946 * Shouldn't this be invalid level on a pathname
6947 * based call ?
6949 if (tran_call != TRANSACT2_SETFILEINFO) {
6950 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
6952 #endif
6953 status = smb_set_file_disposition_info(conn,
6954 pdata,
6955 total_data,
6956 fsp,
6957 smb_fname);
6958 break;
6961 case SMB_FILE_POSITION_INFORMATION:
6963 status = smb_file_position_information(conn,
6964 pdata,
6965 total_data,
6966 fsp);
6967 break;
6970 case SMB_FILE_FULL_EA_INFORMATION:
6972 status = smb_set_file_full_ea_info(conn,
6973 pdata,
6974 total_data,
6975 fsp);
6976 break;
6979 /* From tridge Samba4 :
6980 * MODE_INFORMATION in setfileinfo (I have no
6981 * idea what "mode information" on a file is - it takes a value of 0,
6982 * 2, 4 or 6. What could it be?).
6985 case SMB_FILE_MODE_INFORMATION:
6987 status = smb_file_mode_information(conn,
6988 pdata,
6989 total_data);
6990 break;
6993 /* [MS-SMB2] 3.3.5.21.1 states we MUST fail with STATUS_NOT_SUPPORTED. */
6994 case SMB_FILE_VALID_DATA_LENGTH_INFORMATION:
6995 case SMB_FILE_SHORT_NAME_INFORMATION:
6996 return NT_STATUS_NOT_SUPPORTED;
6998 case SMB_FILE_RENAME_INFORMATION:
7000 status = smb_file_rename_information(conn, req,
7001 pdata, total_data,
7002 fsp, smb_fname);
7003 break;
7006 case SMB2_FILE_RENAME_INFORMATION_INTERNAL:
7008 /* SMB2 rename information. */
7009 status = smb2_file_rename_information(conn, req,
7010 pdata, total_data,
7011 fsp, smb_fname);
7012 break;
7015 case SMB_FILE_LINK_INFORMATION:
7017 status = smb_file_link_information(conn, req,
7018 pdata, total_data,
7019 fsp, smb_fname);
7020 break;
7023 default:
7024 return NT_STATUS_INVALID_LEVEL;
7027 if (!NT_STATUS_IS_OK(status)) {
7028 return status;
7031 *ret_data_size = data_return_size;
7032 return NT_STATUS_OK;
7035 static uint32_t generate_volume_serial_number(
7036 const struct loadparm_substitution *lp_sub,
7037 int snum)
7039 int serial = lp_volume_serial_number(snum);
7040 return serial != -1 ? serial:
7041 str_checksum(lp_servicename(talloc_tos(), lp_sub, snum)) ^
7042 (str_checksum(get_local_machine_name())<<16);