s4:dsdb:tests: Also pass tests if asserted identity is present
[Samba.git] / source3 / smbd / smb2_trans2.c
blob65d8532468d7e37c36623c8781b091f2421b3bc4
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 /****************************************************************************
63 Check if an open file handle is a symlink.
64 ****************************************************************************/
66 NTSTATUS refuse_symlink_fsp(const files_struct *fsp)
69 if (!VALID_STAT(fsp->fsp_name->st)) {
70 return NT_STATUS_ACCESS_DENIED;
72 if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
73 return NT_STATUS_ACCESS_DENIED;
75 if (fsp_get_pathref_fd(fsp) == -1) {
76 return NT_STATUS_ACCESS_DENIED;
78 return NT_STATUS_OK;
81 NTSTATUS check_access_fsp(struct files_struct *fsp,
82 uint32_t access_mask)
84 if (!fsp->fsp_flags.is_fsa) {
85 return smbd_check_access_rights_fsp(fsp->conn->cwd_fsp,
86 fsp,
87 false,
88 access_mask);
90 if (!(fsp->access_mask & access_mask)) {
91 return NT_STATUS_ACCESS_DENIED;
93 return NT_STATUS_OK;
96 #if defined(HAVE_POSIX_ACLS)
97 /****************************************************************************
98 Utility function to open a fsp for a POSIX handle operation.
99 ****************************************************************************/
101 static NTSTATUS get_posix_fsp(connection_struct *conn,
102 struct smb_request *req,
103 struct smb_filename *smb_fname,
104 uint32_t access_mask,
105 files_struct **ret_fsp)
107 NTSTATUS status;
108 uint32_t create_disposition = FILE_OPEN;
109 uint32_t share_access = FILE_SHARE_READ|
110 FILE_SHARE_WRITE|
111 FILE_SHARE_DELETE;
112 struct smb2_create_blobs *posx = NULL;
115 * Only FILE_FLAG_POSIX_SEMANTICS matters on existing files,
116 * but set reasonable defaults.
118 uint32_t file_attributes = 0664;
119 uint32_t oplock = NO_OPLOCK;
120 uint32_t create_options = FILE_NON_DIRECTORY_FILE;
122 /* File or directory must exist. */
123 if (!VALID_STAT(smb_fname->st)) {
124 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
126 /* Cannot be a symlink. */
127 if (S_ISLNK(smb_fname->st.st_ex_mode)) {
128 return NT_STATUS_ACCESS_DENIED;
130 /* Set options correctly for directory open. */
131 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
133 * Only FILE_FLAG_POSIX_SEMANTICS matters on existing
134 * directories, but set reasonable defaults.
136 file_attributes = 0775;
137 create_options = FILE_DIRECTORY_FILE;
140 status = make_smb2_posix_create_ctx(
141 talloc_tos(), &posx, file_attributes);
142 if (!NT_STATUS_IS_OK(status)) {
143 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
144 nt_errstr(status));
145 goto done;
148 status = SMB_VFS_CREATE_FILE(
149 conn, /* conn */
150 req, /* req */
151 smb_fname, /* fname */
152 access_mask, /* access_mask */
153 share_access, /* share_access */
154 create_disposition,/* create_disposition*/
155 create_options, /* create_options */
156 file_attributes,/* file_attributes */
157 oplock, /* oplock_request */
158 NULL, /* lease */
159 0, /* allocation_size */
160 0, /* private_flags */
161 NULL, /* sd */
162 NULL, /* ea_list */
163 ret_fsp, /* result */
164 NULL, /* pinfo */
165 posx, /* in_context */
166 NULL); /* out_context */
168 done:
169 TALLOC_FREE(posx);
170 return status;
172 #endif
174 /********************************************************************
175 Roundup a value to the nearest allocation roundup size boundary.
176 Only do this for Windows clients.
177 ********************************************************************/
179 uint64_t smb_roundup(connection_struct *conn, uint64_t val)
181 uint64_t rval = lp_allocation_roundup_size(SNUM(conn));
183 /* Only roundup for Windows clients. */
184 enum remote_arch_types ra_type = get_remote_arch();
185 if (rval && (ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
186 val = SMB_ROUNDUP(val,rval);
188 return val;
191 /****************************************************************************
192 Utility functions for dealing with extended attributes.
193 ****************************************************************************/
195 /****************************************************************************
196 Refuse to allow clients to overwrite our private xattrs.
197 ****************************************************************************/
199 bool samba_private_attr_name(const char *unix_ea_name)
201 static const char * const prohibited_ea_names[] = {
202 SAMBA_POSIX_INHERITANCE_EA_NAME,
203 SAMBA_XATTR_DOS_ATTRIB,
204 SAMBA_XATTR_MARKER,
205 XATTR_NTACL_NAME,
206 AFPINFO_EA_NETATALK,
207 NULL
210 int i;
212 for (i = 0; prohibited_ea_names[i]; i++) {
213 if (strequal( prohibited_ea_names[i], unix_ea_name))
214 return true;
216 if (strncasecmp_m(unix_ea_name, SAMBA_XATTR_DOSSTREAM_PREFIX,
217 strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) == 0) {
218 return true;
220 return false;
223 /****************************************************************************
224 Get one EA value. Fill in a struct ea_struct.
225 ****************************************************************************/
227 NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx,
228 files_struct *fsp,
229 const char *ea_name,
230 struct ea_struct *pea)
232 /* Get the value of this xattr. Max size is 64k. */
233 size_t attr_size = 256;
234 char *val = NULL;
235 ssize_t sizeret;
236 size_t max_xattr_size = 0;
238 if (fsp == NULL) {
239 return NT_STATUS_INVALID_HANDLE;
242 max_xattr_size = lp_smbd_max_xattr_size(SNUM(fsp->conn));
244 again:
246 val = talloc_realloc(mem_ctx, val, char, attr_size);
247 if (!val) {
248 return NT_STATUS_NO_MEMORY;
251 sizeret = SMB_VFS_FGETXATTR(fsp, ea_name, val, attr_size);
252 if (sizeret == -1 && errno == ERANGE && attr_size < max_xattr_size) {
253 attr_size = max_xattr_size;
254 goto again;
257 if (sizeret == -1) {
258 return map_nt_error_from_unix(errno);
261 DEBUG(10,("get_ea_value: EA %s is of length %u\n", ea_name, (unsigned int)sizeret));
262 dump_data(10, (uint8_t *)val, sizeret);
264 pea->flags = 0;
265 if (strnequal(ea_name, "user.", 5)) {
266 pea->name = talloc_strdup(mem_ctx, &ea_name[5]);
267 } else {
268 pea->name = talloc_strdup(mem_ctx, ea_name);
270 if (pea->name == NULL) {
271 TALLOC_FREE(val);
272 return NT_STATUS_NO_MEMORY;
274 pea->value.data = (unsigned char *)val;
275 pea->value.length = (size_t)sizeret;
276 return NT_STATUS_OK;
279 NTSTATUS get_ea_names_from_fsp(TALLOC_CTX *mem_ctx,
280 files_struct *fsp,
281 char ***pnames,
282 size_t *pnum_names)
284 char smallbuf[1024];
285 /* Get a list of all xattrs. Max namesize is 64k. */
286 size_t ea_namelist_size = 1024;
287 char *ea_namelist = smallbuf;
288 char *to_free = NULL;
290 char *p;
291 char **names;
292 size_t num_names;
293 ssize_t sizeret = -1;
294 NTSTATUS status;
296 if (pnames) {
297 *pnames = NULL;
299 *pnum_names = 0;
301 if (fsp == NULL) {
303 * Callers may pass fsp == NULL when passing smb_fname->fsp of a
304 * symlink. This is ok, handle it here, by just return no EA's
305 * on a symlink.
307 return NT_STATUS_OK;
310 /* should be the case that fsp != NULL */
311 SMB_ASSERT(fsp != NULL);
313 sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
314 ea_namelist_size);
316 if ((sizeret == -1) && (errno == ERANGE)) {
317 ea_namelist_size = 65536;
318 ea_namelist = talloc_array(mem_ctx, char, ea_namelist_size);
319 if (ea_namelist == NULL) {
320 return NT_STATUS_NO_MEMORY;
322 to_free = ea_namelist;
324 sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
325 ea_namelist_size);
328 if (sizeret == -1) {
329 status = map_nt_error_from_unix(errno);
330 TALLOC_FREE(to_free);
331 return status;
334 DBG_DEBUG("ea_namelist size = %zd\n", sizeret);
336 if (sizeret == 0) {
337 TALLOC_FREE(to_free);
338 return NT_STATUS_OK;
342 * Ensure the result is 0-terminated
345 if (ea_namelist[sizeret-1] != '\0') {
346 TALLOC_FREE(to_free);
347 return NT_STATUS_INTERNAL_ERROR;
351 * count the names
353 num_names = 0;
355 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
356 num_names += 1;
359 *pnum_names = num_names;
361 if (pnames == NULL) {
362 TALLOC_FREE(to_free);
363 return NT_STATUS_OK;
366 names = talloc_array(mem_ctx, char *, num_names);
367 if (names == NULL) {
368 DEBUG(0, ("talloc failed\n"));
369 TALLOC_FREE(to_free);
370 return NT_STATUS_NO_MEMORY;
373 if (ea_namelist == smallbuf) {
374 ea_namelist = talloc_memdup(names, smallbuf, sizeret);
375 if (ea_namelist == NULL) {
376 TALLOC_FREE(names);
377 return NT_STATUS_NO_MEMORY;
379 } else {
380 talloc_steal(names, ea_namelist);
382 ea_namelist = talloc_realloc(names, ea_namelist, char,
383 sizeret);
384 if (ea_namelist == NULL) {
385 TALLOC_FREE(names);
386 return NT_STATUS_NO_MEMORY;
390 num_names = 0;
392 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
393 names[num_names++] = p;
396 *pnames = names;
398 return NT_STATUS_OK;
401 /****************************************************************************
402 Return a linked list of the total EA's. Plus the total size
403 ****************************************************************************/
405 static NTSTATUS get_ea_list_from_fsp(TALLOC_CTX *mem_ctx,
406 files_struct *fsp,
407 size_t *pea_total_len,
408 struct ea_list **ea_list)
410 /* Get a list of all xattrs. Max namesize is 64k. */
411 size_t i, num_names;
412 char **names;
413 struct ea_list *ea_list_head = NULL;
414 bool posix_pathnames = false;
415 NTSTATUS status;
417 *pea_total_len = 0;
418 *ea_list = NULL;
420 /* symlink */
421 if (fsp == NULL) {
422 return NT_STATUS_OK;
425 if (!lp_ea_support(SNUM(fsp->conn))) {
426 return NT_STATUS_OK;
429 if (fsp_is_alternate_stream(fsp)) {
430 return NT_STATUS_INVALID_PARAMETER;
433 posix_pathnames = (fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH);
435 status = get_ea_names_from_fsp(talloc_tos(),
436 fsp,
437 &names,
438 &num_names);
440 if (!NT_STATUS_IS_OK(status)) {
441 return status;
444 if (num_names == 0) {
445 return NT_STATUS_OK;
448 for (i=0; i<num_names; i++) {
449 struct ea_list *listp;
450 fstring dos_ea_name;
452 if (strnequal(names[i], "system.", 7)
453 || samba_private_attr_name(names[i]))
454 continue;
457 * Filter out any underlying POSIX EA names
458 * that a Windows client can't handle.
460 if (!posix_pathnames &&
461 is_invalid_windows_ea_name(names[i])) {
462 continue;
465 listp = talloc(mem_ctx, struct ea_list);
466 if (listp == NULL) {
467 return NT_STATUS_NO_MEMORY;
470 status = get_ea_value_fsp(listp,
471 fsp,
472 names[i],
473 &listp->ea);
475 if (!NT_STATUS_IS_OK(status)) {
476 TALLOC_FREE(listp);
477 return status;
480 if (listp->ea.value.length == 0) {
482 * We can never return a zero length EA.
483 * Windows reports the EA's as corrupted.
485 TALLOC_FREE(listp);
486 continue;
487 } else if (listp->ea.value.length > 65536) {
489 * SMB clients may report error with file
490 * if large EA is presented to them.
492 DBG_ERR("EA [%s] on file [%s] exceeds "
493 "maximum permitted EA size of 64KiB: %zu\n.",
494 listp->ea.name, fsp_str_dbg(fsp),
495 listp->ea.value.length);
496 TALLOC_FREE(listp);
497 continue;
500 push_ascii_fstring(dos_ea_name, listp->ea.name);
502 *pea_total_len +=
503 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
505 DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len "
506 "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
507 (unsigned int)listp->ea.value.length));
509 DLIST_ADD_END(ea_list_head, listp);
513 /* Add on 4 for total length. */
514 if (*pea_total_len) {
515 *pea_total_len += 4;
518 DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
519 (unsigned int)*pea_total_len));
521 *ea_list = ea_list_head;
522 return NT_STATUS_OK;
525 /****************************************************************************
526 Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer
527 that was filled.
528 ****************************************************************************/
530 static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
531 connection_struct *conn, struct ea_list *ea_list)
533 unsigned int ret_data_size = 4;
534 char *p = pdata;
536 SMB_ASSERT(total_data_size >= 4);
538 if (!lp_ea_support(SNUM(conn))) {
539 SIVAL(pdata,4,0);
540 return 4;
543 for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
544 size_t dos_namelen;
545 fstring dos_ea_name;
546 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
547 dos_namelen = strlen(dos_ea_name);
548 if (dos_namelen > 255 || dos_namelen == 0) {
549 break;
551 if (ea_list->ea.value.length > 65535) {
552 break;
554 if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
555 break;
558 /* We know we have room. */
559 SCVAL(p,0,ea_list->ea.flags);
560 SCVAL(p,1,dos_namelen);
561 SSVAL(p,2,ea_list->ea.value.length);
562 strlcpy(p+4, dos_ea_name, dos_namelen+1);
563 if (ea_list->ea.value.length > 0) {
564 memcpy(p + 4 + dos_namelen + 1,
565 ea_list->ea.value.data,
566 ea_list->ea.value.length);
569 total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
570 p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
573 ret_data_size = PTR_DIFF(p, pdata);
574 DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
575 SIVAL(pdata,0,ret_data_size);
576 return ret_data_size;
579 static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
580 char *pdata,
581 unsigned int total_data_size,
582 unsigned int *ret_data_size,
583 connection_struct *conn,
584 struct ea_list *ea_list)
586 uint8_t *p = (uint8_t *)pdata;
587 uint8_t *last_start = NULL;
588 bool do_store_data = (pdata != NULL);
590 *ret_data_size = 0;
592 if (!lp_ea_support(SNUM(conn))) {
593 return NT_STATUS_NO_EAS_ON_FILE;
596 for (; ea_list; ea_list = ea_list->next) {
597 size_t dos_namelen;
598 fstring dos_ea_name;
599 size_t this_size;
600 size_t pad = 0;
602 if (last_start != NULL && do_store_data) {
603 SIVAL(last_start, 0, PTR_DIFF(p, last_start));
605 last_start = p;
607 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
608 dos_namelen = strlen(dos_ea_name);
609 if (dos_namelen > 255 || dos_namelen == 0) {
610 return NT_STATUS_INTERNAL_ERROR;
612 if (ea_list->ea.value.length > 65535) {
613 return NT_STATUS_INTERNAL_ERROR;
616 this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length;
618 if (ea_list->next) {
619 pad = (4 - (this_size % 4)) % 4;
620 this_size += pad;
623 if (do_store_data) {
624 if (this_size > total_data_size) {
625 return NT_STATUS_INFO_LENGTH_MISMATCH;
628 /* We know we have room. */
629 SIVAL(p, 0x00, 0); /* next offset */
630 SCVAL(p, 0x04, ea_list->ea.flags);
631 SCVAL(p, 0x05, dos_namelen);
632 SSVAL(p, 0x06, ea_list->ea.value.length);
633 strlcpy((char *)(p+0x08), dos_ea_name, dos_namelen+1);
634 memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
635 if (pad) {
636 memset(p + 0x08 + dos_namelen + 1 + ea_list->ea.value.length,
637 '\0',
638 pad);
640 total_data_size -= this_size;
643 p += this_size;
646 *ret_data_size = PTR_DIFF(p, pdata);
647 DEBUG(10,("fill_ea_chained_buffer: data_size = %u\n", *ret_data_size));
648 return NT_STATUS_OK;
651 unsigned int estimate_ea_size(files_struct *fsp)
653 size_t total_ea_len = 0;
654 TALLOC_CTX *mem_ctx;
655 struct ea_list *ea_list = NULL;
656 NTSTATUS status;
658 /* symlink */
659 if (fsp == NULL) {
660 return 0;
663 if (!lp_ea_support(SNUM(fsp->conn))) {
664 return 0;
667 mem_ctx = talloc_stackframe();
669 /* If this is a stream fsp, then we need to instead find the
670 * estimated ea len from the main file, not the stream
671 * (streams cannot have EAs), but the estimate isn't just 0 in
672 * this case! */
673 fsp = metadata_fsp(fsp);
674 (void)get_ea_list_from_fsp(mem_ctx,
675 fsp,
676 &total_ea_len,
677 &ea_list);
679 if(fsp->conn->sconn->using_smb2) {
680 unsigned int ret_data_size;
682 * We're going to be using fill_ea_chained_buffer() to
683 * marshall EA's - this size is significantly larger
684 * than the SMB1 buffer. Re-calculate the size without
685 * marshalling.
687 status = fill_ea_chained_buffer(mem_ctx,
688 NULL,
690 &ret_data_size,
691 fsp->conn,
692 ea_list);
693 if (!NT_STATUS_IS_OK(status)) {
694 ret_data_size = 0;
696 total_ea_len = ret_data_size;
698 TALLOC_FREE(mem_ctx);
699 return total_ea_len;
702 /****************************************************************************
703 Ensure the EA name is case insensitive by matching any existing EA name.
704 ****************************************************************************/
706 static void canonicalize_ea_name(files_struct *fsp,
707 fstring unix_ea_name)
709 size_t total_ea_len;
710 TALLOC_CTX *mem_ctx = talloc_tos();
711 struct ea_list *ea_list;
712 NTSTATUS status = get_ea_list_from_fsp(mem_ctx,
713 fsp,
714 &total_ea_len,
715 &ea_list);
716 if (!NT_STATUS_IS_OK(status)) {
717 return;
720 for (; ea_list; ea_list = ea_list->next) {
721 if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
722 DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
723 &unix_ea_name[5], ea_list->ea.name));
724 strlcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-5);
725 break;
730 /****************************************************************************
731 Set or delete an extended attribute.
732 ****************************************************************************/
734 NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
735 struct ea_list *ea_list)
737 NTSTATUS status;
738 bool posix_pathnames = false;
740 if (!lp_ea_support(SNUM(conn))) {
741 return NT_STATUS_EAS_NOT_SUPPORTED;
744 if (fsp == NULL) {
745 return NT_STATUS_INVALID_HANDLE;
748 posix_pathnames = (fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH);
750 status = refuse_symlink_fsp(fsp);
751 if (!NT_STATUS_IS_OK(status)) {
752 return status;
755 status = check_access_fsp(fsp, FILE_WRITE_EA);
756 if (!NT_STATUS_IS_OK(status)) {
757 return status;
760 /* Setting EAs on streams isn't supported. */
761 if (fsp_is_alternate_stream(fsp)) {
762 return NT_STATUS_INVALID_PARAMETER;
766 * Filter out invalid Windows EA names - before
767 * we set *any* of them.
770 if (!posix_pathnames && ea_list_has_invalid_name(ea_list)) {
771 return STATUS_INVALID_EA_NAME;
774 for (;ea_list; ea_list = ea_list->next) {
775 int ret;
776 fstring unix_ea_name;
778 fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
779 fstrcat(unix_ea_name, ea_list->ea.name);
781 canonicalize_ea_name(fsp, unix_ea_name);
783 DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
785 if (samba_private_attr_name(unix_ea_name)) {
786 DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
787 return NT_STATUS_ACCESS_DENIED;
790 if (ea_list->ea.value.length == 0) {
791 /* Remove the attribute. */
792 DBG_DEBUG("deleting ea name %s on "
793 "file %s by file descriptor.\n",
794 unix_ea_name, fsp_str_dbg(fsp));
795 ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name);
796 #ifdef ENOATTR
797 /* Removing a non existent attribute always succeeds. */
798 if (ret == -1 && errno == ENOATTR) {
799 DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",
800 unix_ea_name));
801 ret = 0;
803 #endif
804 } else {
805 DEBUG(10,("set_ea: setting ea name %s on file "
806 "%s by file descriptor.\n",
807 unix_ea_name, fsp_str_dbg(fsp)));
808 ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name,
809 ea_list->ea.value.data, ea_list->ea.value.length, 0);
812 if (ret == -1) {
813 #ifdef ENOTSUP
814 if (errno == ENOTSUP) {
815 return NT_STATUS_EAS_NOT_SUPPORTED;
817 #endif
818 return map_nt_error_from_unix(errno);
822 return NT_STATUS_OK;
825 /****************************************************************************
826 Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
827 ****************************************************************************/
829 struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
831 struct ea_list *ea_list_head = NULL;
832 size_t offset = 0;
833 size_t bytes_used = 0;
835 while (offset < data_size) {
836 struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);
838 if (!eal) {
839 return NULL;
842 DLIST_ADD_END(ea_list_head, eal);
843 offset += bytes_used;
846 return ea_list_head;
849 /****************************************************************************
850 Count the total EA size needed.
851 ****************************************************************************/
853 static size_t ea_list_size(struct ea_list *ealist)
855 fstring dos_ea_name;
856 struct ea_list *listp;
857 size_t ret = 0;
859 for (listp = ealist; listp; listp = listp->next) {
860 push_ascii_fstring(dos_ea_name, listp->ea.name);
861 ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
863 /* Add on 4 for total length. */
864 if (ret) {
865 ret += 4;
868 return ret;
871 /****************************************************************************
872 Return a union of EA's from a file list and a list of names.
873 The TALLOC context for the two lists *MUST* be identical as we steal
874 memory from one list to add to another. JRA.
875 ****************************************************************************/
877 static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *file_list, size_t *total_ea_len)
879 struct ea_list *nlistp, *flistp;
881 for (nlistp = name_list; nlistp; nlistp = nlistp->next) {
882 for (flistp = file_list; flistp; flistp = flistp->next) {
883 if (strequal(nlistp->ea.name, flistp->ea.name)) {
884 break;
888 if (flistp) {
889 /* Copy the data from this entry. */
890 nlistp->ea.flags = flistp->ea.flags;
891 nlistp->ea.value = flistp->ea.value;
892 } else {
893 /* Null entry. */
894 nlistp->ea.flags = 0;
895 ZERO_STRUCT(nlistp->ea.value);
899 *total_ea_len = ea_list_size(name_list);
900 return name_list;
903 /*********************************************************
904 Routine to check if a given string matches exactly.
905 as a special case a mask of "." does NOT match. That
906 is required for correct wildcard semantics
907 Case can be significant or not.
908 **********************************************************/
910 static bool exact_match(bool has_wild,
911 bool case_sensitive,
912 const char *str,
913 const char *mask)
915 if (mask[0] == '.' && mask[1] == 0) {
916 return false;
919 if (has_wild) {
920 return false;
923 if (case_sensitive) {
924 return strcmp(str,mask)==0;
925 } else {
926 return strcasecmp_m(str,mask) == 0;
930 /****************************************************************************
931 Return the filetype for UNIX extensions.
932 ****************************************************************************/
934 static uint32_t unix_filetype(mode_t mode)
936 if(S_ISREG(mode))
937 return UNIX_TYPE_FILE;
938 else if(S_ISDIR(mode))
939 return UNIX_TYPE_DIR;
940 #ifdef S_ISLNK
941 else if(S_ISLNK(mode))
942 return UNIX_TYPE_SYMLINK;
943 #endif
944 #ifdef S_ISCHR
945 else if(S_ISCHR(mode))
946 return UNIX_TYPE_CHARDEV;
947 #endif
948 #ifdef S_ISBLK
949 else if(S_ISBLK(mode))
950 return UNIX_TYPE_BLKDEV;
951 #endif
952 #ifdef S_ISFIFO
953 else if(S_ISFIFO(mode))
954 return UNIX_TYPE_FIFO;
955 #endif
956 #ifdef S_ISSOCK
957 else if(S_ISSOCK(mode))
958 return UNIX_TYPE_SOCKET;
959 #endif
961 DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode));
962 return UNIX_TYPE_UNKNOWN;
965 /****************************************************************************
966 Map wire perms onto standard UNIX permissions. Obey share restrictions.
967 ****************************************************************************/
969 NTSTATUS unix_perms_from_wire(connection_struct *conn,
970 const SMB_STRUCT_STAT *psbuf,
971 uint32_t perms,
972 enum perm_type ptype,
973 mode_t *ret_perms)
975 mode_t ret = 0;
977 if (perms == SMB_MODE_NO_CHANGE) {
978 if (!VALID_STAT(*psbuf)) {
979 return NT_STATUS_INVALID_PARAMETER;
980 } else {
981 *ret_perms = psbuf->st_ex_mode;
982 return NT_STATUS_OK;
986 ret = wire_perms_to_unix(perms);
988 if (ptype == PERM_NEW_FILE) {
990 * "create mask"/"force create mode" are
991 * only applied to new files, not existing ones.
993 ret &= lp_create_mask(SNUM(conn));
994 /* Add in force bits */
995 ret |= lp_force_create_mode(SNUM(conn));
996 } else if (ptype == PERM_NEW_DIR) {
998 * "directory mask"/"force directory mode" are
999 * only applied to new directories, not existing ones.
1001 ret &= lp_directory_mask(SNUM(conn));
1002 /* Add in force bits */
1003 ret |= lp_force_directory_mode(SNUM(conn));
1006 *ret_perms = ret;
1007 return NT_STATUS_OK;
1010 /****************************************************************************
1011 Needed to show the msdfs symlinks as directories. Modifies psbuf
1012 to be a directory if it's a msdfs link.
1013 ****************************************************************************/
1015 static bool check_msdfs_link(struct files_struct *dirfsp,
1016 struct smb_filename *atname,
1017 struct smb_filename *smb_fname)
1019 int saved_errno = errno;
1020 if(lp_host_msdfs() &&
1021 lp_msdfs_root(SNUM(dirfsp->conn)) &&
1022 is_msdfs_link(dirfsp, atname)) {
1025 * Copy the returned stat struct from the relative
1026 * to the full pathname.
1028 smb_fname->st = atname->st;
1030 DEBUG(5,("check_msdfs_link: Masquerading msdfs link %s "
1031 "as a directory\n",
1032 smb_fname->base_name));
1033 smb_fname->st.st_ex_mode =
1034 (smb_fname->st.st_ex_mode & 0xFFF) | S_IFDIR;
1035 errno = saved_errno;
1036 return true;
1038 errno = saved_errno;
1039 return false;
1043 /****************************************************************************
1044 Get a level dependent lanman2 dir entry.
1045 ****************************************************************************/
1047 struct smbd_dirptr_lanman2_state {
1048 connection_struct *conn;
1049 uint32_t info_level;
1050 bool check_mangled_names;
1051 bool has_wild;
1052 bool got_exact_match;
1053 bool case_sensitive;
1056 static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx,
1057 void *private_data,
1058 const char *dname,
1059 const char *mask,
1060 char **_fname)
1062 struct smbd_dirptr_lanman2_state *state =
1063 (struct smbd_dirptr_lanman2_state *)private_data;
1064 bool ok;
1065 char mangled_name[13]; /* mangled 8.3 name. */
1066 bool got_match;
1067 const char *fname;
1069 /* Mangle fname if it's an illegal name. */
1070 if (mangle_must_mangle(dname, state->conn->params)) {
1072 * Slow path - ensure we can push the original name as UCS2. If
1073 * not, then just don't return this name.
1075 NTSTATUS status;
1076 size_t ret_len = 0;
1077 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1078 uint8_t *tmp = talloc_array(talloc_tos(),
1079 uint8_t,
1080 len);
1082 status = srvstr_push(NULL,
1083 FLAGS2_UNICODE_STRINGS,
1084 tmp,
1085 dname,
1086 len,
1087 STR_TERMINATE,
1088 &ret_len);
1090 TALLOC_FREE(tmp);
1092 if (!NT_STATUS_IS_OK(status)) {
1093 return false;
1096 ok = name_to_8_3(dname, mangled_name,
1097 true, state->conn->params);
1098 if (!ok) {
1099 return false;
1101 fname = mangled_name;
1102 } else {
1103 fname = dname;
1106 got_match = exact_match(state->has_wild,
1107 state->case_sensitive,
1108 fname, mask);
1109 state->got_exact_match = got_match;
1110 if (!got_match) {
1111 got_match = mask_match(fname, mask,
1112 state->case_sensitive);
1115 if(!got_match && state->check_mangled_names &&
1116 !mangle_is_8_3(fname, false, state->conn->params)) {
1118 * It turns out that NT matches wildcards against
1119 * both long *and* short names. This may explain some
1120 * of the wildcard wierdness from old DOS clients
1121 * that some people have been seeing.... JRA.
1123 /* Force the mangling into 8.3. */
1124 ok = name_to_8_3(fname, mangled_name,
1125 false, state->conn->params);
1126 if (!ok) {
1127 return false;
1130 got_match = exact_match(state->has_wild,
1131 state->case_sensitive,
1132 mangled_name, mask);
1133 state->got_exact_match = got_match;
1134 if (!got_match) {
1135 got_match = mask_match(mangled_name, mask,
1136 state->case_sensitive);
1140 if (!got_match) {
1141 return false;
1144 *_fname = talloc_strdup(ctx, fname);
1145 if (*_fname == NULL) {
1146 return false;
1149 return true;
1152 static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
1153 void *private_data,
1154 struct files_struct *dirfsp,
1155 struct smb_filename *atname,
1156 struct smb_filename *smb_fname,
1157 bool get_dosmode,
1158 uint32_t *_mode)
1160 struct smbd_dirptr_lanman2_state *state =
1161 (struct smbd_dirptr_lanman2_state *)private_data;
1162 bool ms_dfs_link = false;
1164 if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
1165 if (SMB_VFS_LSTAT(state->conn, smb_fname) != 0) {
1166 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1167 "Couldn't lstat [%s] (%s)\n",
1168 smb_fname_str_dbg(smb_fname),
1169 strerror(errno)));
1170 return false;
1172 return true;
1175 if (!VALID_STAT(smb_fname->st) &&
1176 SMB_VFS_STAT(state->conn, smb_fname) != 0) {
1177 /* Needed to show the msdfs symlinks as
1178 * directories */
1180 ms_dfs_link = check_msdfs_link(dirfsp,
1181 atname,
1182 smb_fname);
1183 if (!ms_dfs_link) {
1184 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1185 "Couldn't stat [%s] (%s)\n",
1186 smb_fname_str_dbg(smb_fname),
1187 strerror(errno)));
1188 return false;
1191 *_mode = dos_mode_msdfs(state->conn, smb_fname);
1192 return true;
1195 if (!get_dosmode) {
1196 return true;
1199 *_mode = fdos_mode(smb_fname->fsp);
1200 smb_fname->st = smb_fname->fsp->fsp_name->st;
1202 return true;
1205 static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
1206 connection_struct *conn,
1207 uint16_t flags2,
1208 uint32_t info_level,
1209 struct ea_list *name_list,
1210 bool check_mangled_names,
1211 bool requires_resume_key,
1212 uint32_t mode,
1213 const char *fname,
1214 const struct smb_filename *smb_fname,
1215 int space_remaining,
1216 uint8_t align,
1217 bool do_pad,
1218 char *base_data,
1219 char **ppdata,
1220 char *end_data,
1221 uint64_t *last_entry_off)
1223 char *p, *q, *pdata = *ppdata;
1224 uint32_t reskey=0;
1225 uint64_t file_size = 0;
1226 uint64_t allocation_size = 0;
1227 uint64_t file_id = 0;
1228 size_t len = 0;
1229 struct timespec mdate_ts = {0};
1230 struct timespec adate_ts = {0};
1231 struct timespec cdate_ts = {0};
1232 struct timespec create_date_ts = {0};
1233 time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
1234 char *nameptr;
1235 char *last_entry_ptr;
1236 bool was_8_3;
1237 int off;
1238 int pad = 0;
1239 NTSTATUS status;
1240 struct readdir_attr_data *readdir_attr_data = NULL;
1242 if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) {
1243 file_size = get_file_size_stat(&smb_fname->st);
1245 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
1248 * Skip SMB_VFS_FREADDIR_ATTR if the directory entry is a symlink or
1249 * a DFS symlink.
1251 if (smb_fname->fsp != NULL &&
1252 !(mode & FILE_ATTRIBUTE_REPARSE_POINT)) {
1253 status = SMB_VFS_FREADDIR_ATTR(smb_fname->fsp,
1254 ctx,
1255 &readdir_attr_data);
1256 if (!NT_STATUS_IS_OK(status)) {
1257 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_SUPPORTED,
1258 status)) {
1259 return status;
1264 file_id = SMB_VFS_FS_FILE_ID(conn, &smb_fname->st);
1266 mdate_ts = smb_fname->st.st_ex_mtime;
1267 adate_ts = smb_fname->st.st_ex_atime;
1268 create_date_ts = get_create_timespec(conn, NULL, smb_fname);
1269 cdate_ts = get_change_timespec(conn, NULL, smb_fname);
1271 if (lp_dos_filetime_resolution(SNUM(conn))) {
1272 dos_filetime_timespec(&create_date_ts);
1273 dos_filetime_timespec(&mdate_ts);
1274 dos_filetime_timespec(&adate_ts);
1275 dos_filetime_timespec(&cdate_ts);
1278 create_date = convert_timespec_to_time_t(create_date_ts);
1279 mdate = convert_timespec_to_time_t(mdate_ts);
1280 adate = convert_timespec_to_time_t(adate_ts);
1282 /* align the record */
1283 SMB_ASSERT(align >= 1);
1285 off = (int)PTR_DIFF(pdata, base_data);
1286 pad = (off + (align-1)) & ~(align-1);
1287 pad -= off;
1289 if (pad && pad > space_remaining) {
1290 DEBUG(9,("smbd_marshall_dir_entry: out of space "
1291 "for padding (wanted %u, had %d)\n",
1292 (unsigned int)pad,
1293 space_remaining ));
1294 return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
1297 off += pad;
1298 /* initialize padding to 0 */
1299 if (pad) {
1300 memset(pdata, 0, pad);
1302 space_remaining -= pad;
1304 DEBUG(10,("smbd_marshall_dir_entry: space_remaining = %d\n",
1305 space_remaining ));
1307 pdata += pad;
1308 p = pdata;
1309 last_entry_ptr = p;
1311 pad = 0;
1312 off = 0;
1314 switch (info_level) {
1315 case SMB_FIND_INFO_STANDARD:
1316 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_INFO_STANDARD\n"));
1317 if(requires_resume_key) {
1318 SIVAL(p,0,reskey);
1319 p += 4;
1321 srv_put_dos_date2(p,0,create_date);
1322 srv_put_dos_date2(p,4,adate);
1323 srv_put_dos_date2(p,8,mdate);
1324 SIVAL(p,12,(uint32_t)file_size);
1325 SIVAL(p,16,(uint32_t)allocation_size);
1326 SSVAL(p,20,mode);
1327 p += 23;
1328 nameptr = p;
1329 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1330 p += ucs2_align(base_data, p, 0);
1332 status = srvstr_push(base_data, flags2, p,
1333 fname, PTR_DIFF(end_data, p),
1334 STR_TERMINATE, &len);
1335 if (!NT_STATUS_IS_OK(status)) {
1336 return status;
1338 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1339 if (len > 2) {
1340 SCVAL(nameptr, -1, len - 2);
1341 } else {
1342 SCVAL(nameptr, -1, 0);
1344 } else {
1345 if (len > 1) {
1346 SCVAL(nameptr, -1, len - 1);
1347 } else {
1348 SCVAL(nameptr, -1, 0);
1351 p += len;
1352 break;
1354 case SMB_FIND_EA_SIZE:
1355 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_SIZE\n"));
1356 if (requires_resume_key) {
1357 SIVAL(p,0,reskey);
1358 p += 4;
1360 srv_put_dos_date2(p,0,create_date);
1361 srv_put_dos_date2(p,4,adate);
1362 srv_put_dos_date2(p,8,mdate);
1363 SIVAL(p,12,(uint32_t)file_size);
1364 SIVAL(p,16,(uint32_t)allocation_size);
1365 SSVAL(p,20,mode);
1367 unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1368 SIVAL(p,22,ea_size); /* Extended attributes */
1370 p += 27;
1371 nameptr = p - 1;
1372 status = srvstr_push(base_data, flags2,
1373 p, fname, PTR_DIFF(end_data, p),
1374 STR_TERMINATE | STR_NOALIGN, &len);
1375 if (!NT_STATUS_IS_OK(status)) {
1376 return status;
1378 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1379 if (len > 2) {
1380 len -= 2;
1381 } else {
1382 len = 0;
1384 } else {
1385 if (len > 1) {
1386 len -= 1;
1387 } else {
1388 len = 0;
1391 SCVAL(nameptr,0,len);
1392 p += len;
1393 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1394 break;
1396 case SMB_FIND_EA_LIST:
1398 struct ea_list *file_list = NULL;
1399 size_t ea_len = 0;
1401 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_LIST\n"));
1402 if (!name_list) {
1403 return NT_STATUS_INVALID_PARAMETER;
1405 if (requires_resume_key) {
1406 SIVAL(p,0,reskey);
1407 p += 4;
1409 srv_put_dos_date2(p,0,create_date);
1410 srv_put_dos_date2(p,4,adate);
1411 srv_put_dos_date2(p,8,mdate);
1412 SIVAL(p,12,(uint32_t)file_size);
1413 SIVAL(p,16,(uint32_t)allocation_size);
1414 SSVAL(p,20,mode);
1415 p += 22; /* p now points to the EA area. */
1417 status = get_ea_list_from_fsp(ctx,
1418 smb_fname->fsp,
1419 &ea_len, &file_list);
1420 if (!NT_STATUS_IS_OK(status)) {
1421 file_list = NULL;
1423 name_list = ea_list_union(name_list, file_list, &ea_len);
1425 /* We need to determine if this entry will fit in the space available. */
1426 /* Max string size is 255 bytes. */
1427 if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
1428 DEBUG(9,("smbd_marshall_dir_entry: out of space "
1429 "(wanted %u, had %d)\n",
1430 (unsigned int)PTR_DIFF(p + 255 + ea_len,pdata),
1431 space_remaining ));
1432 return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
1435 /* Push the ea_data followed by the name. */
1436 p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
1437 nameptr = p;
1438 status = srvstr_push(base_data, flags2,
1439 p + 1, fname, PTR_DIFF(end_data, p+1),
1440 STR_TERMINATE | STR_NOALIGN, &len);
1441 if (!NT_STATUS_IS_OK(status)) {
1442 return status;
1444 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1445 if (len > 2) {
1446 len -= 2;
1447 } else {
1448 len = 0;
1450 } else {
1451 if (len > 1) {
1452 len -= 1;
1453 } else {
1454 len = 0;
1457 SCVAL(nameptr,0,len);
1458 p += len + 1;
1459 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1460 break;
1463 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
1464 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
1465 was_8_3 = mangle_is_8_3(fname, True, conn->params);
1466 p += 4;
1467 SIVAL(p,0,reskey); p += 4;
1468 put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1469 put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1470 put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1471 put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1472 SOFF_T(p,0,file_size); p += 8;
1473 SOFF_T(p,0,allocation_size); p += 8;
1474 SIVAL(p,0,mode); p += 4;
1475 q = p; p += 4; /* q is placeholder for name length. */
1476 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1477 SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1478 } else {
1479 unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1480 SIVAL(p,0,ea_size); /* Extended attributes */
1482 p += 4;
1483 /* Clear the short name buffer. This is
1484 * IMPORTANT as not doing so will trigger
1485 * a Win2k client bug. JRA.
1487 if (!was_8_3 && check_mangled_names) {
1488 char mangled_name[13]; /* mangled 8.3 name. */
1489 if (!name_to_8_3(fname,mangled_name,True,
1490 conn->params)) {
1491 /* Error - mangle failed ! */
1492 memset(mangled_name,'\0',12);
1494 mangled_name[12] = 0;
1495 status = srvstr_push(base_data, flags2,
1496 p+2, mangled_name, 24,
1497 STR_UPPER|STR_UNICODE, &len);
1498 if (!NT_STATUS_IS_OK(status)) {
1499 return status;
1501 if (len < 24) {
1502 memset(p + 2 + len,'\0',24 - len);
1504 SSVAL(p, 0, len);
1505 } else {
1506 memset(p,'\0',26);
1508 p += 2 + 24;
1509 status = srvstr_push(base_data, flags2, p,
1510 fname, PTR_DIFF(end_data, p),
1511 STR_TERMINATE_ASCII, &len);
1512 if (!NT_STATUS_IS_OK(status)) {
1513 return status;
1515 SIVAL(q,0,len);
1516 p += len;
1518 len = PTR_DIFF(p, pdata);
1519 pad = (len + (align-1)) & ~(align-1);
1521 * offset to the next entry, the caller
1522 * will overwrite it for the last entry
1523 * that's why we always include the padding
1525 SIVAL(pdata,0,pad);
1527 * set padding to zero
1529 if (do_pad) {
1530 memset(p, 0, pad - len);
1531 p = pdata + pad;
1532 } else {
1533 p = pdata + len;
1535 break;
1537 case SMB_FIND_FILE_DIRECTORY_INFO:
1538 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
1539 p += 4;
1540 SIVAL(p,0,reskey); p += 4;
1541 put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1542 put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1543 put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1544 put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1545 SOFF_T(p,0,file_size); p += 8;
1546 SOFF_T(p,0,allocation_size); p += 8;
1547 SIVAL(p,0,mode); p += 4;
1548 status = srvstr_push(base_data, flags2,
1549 p + 4, fname, PTR_DIFF(end_data, p+4),
1550 STR_TERMINATE_ASCII, &len);
1551 if (!NT_STATUS_IS_OK(status)) {
1552 return status;
1554 SIVAL(p,0,len);
1555 p += 4 + len;
1557 len = PTR_DIFF(p, pdata);
1558 pad = (len + (align-1)) & ~(align-1);
1560 * offset to the next entry, the caller
1561 * will overwrite it for the last entry
1562 * that's why we always include the padding
1564 SIVAL(pdata,0,pad);
1566 * set padding to zero
1568 if (do_pad) {
1569 memset(p, 0, pad - len);
1570 p = pdata + pad;
1571 } else {
1572 p = pdata + len;
1574 break;
1576 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
1577 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
1578 p += 4;
1579 SIVAL(p,0,reskey); p += 4;
1580 put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1581 put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1582 put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1583 put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1584 SOFF_T(p,0,file_size); p += 8;
1585 SOFF_T(p,0,allocation_size); p += 8;
1586 SIVAL(p,0,mode); p += 4;
1587 q = p; p += 4; /* q is placeholder for name length. */
1588 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1589 SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1590 } else {
1591 unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1592 SIVAL(p,0,ea_size); /* Extended attributes */
1594 p +=4;
1595 status = srvstr_push(base_data, flags2, p,
1596 fname, PTR_DIFF(end_data, p),
1597 STR_TERMINATE_ASCII, &len);
1598 if (!NT_STATUS_IS_OK(status)) {
1599 return status;
1601 SIVAL(q, 0, len);
1602 p += len;
1604 len = PTR_DIFF(p, pdata);
1605 pad = (len + (align-1)) & ~(align-1);
1607 * offset to the next entry, the caller
1608 * will overwrite it for the last entry
1609 * that's why we always include the padding
1611 SIVAL(pdata,0,pad);
1613 * set padding to zero
1615 if (do_pad) {
1616 memset(p, 0, pad - len);
1617 p = pdata + pad;
1618 } else {
1619 p = pdata + len;
1621 break;
1623 case SMB_FIND_FILE_NAMES_INFO:
1624 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
1625 p += 4;
1626 SIVAL(p,0,reskey); p += 4;
1627 p += 4;
1628 /* this must *not* be null terminated or w2k gets in a loop trying to set an
1629 acl on a dir (tridge) */
1630 status = srvstr_push(base_data, flags2, p,
1631 fname, PTR_DIFF(end_data, p),
1632 STR_TERMINATE_ASCII, &len);
1633 if (!NT_STATUS_IS_OK(status)) {
1634 return status;
1636 SIVAL(p, -4, len);
1637 p += len;
1639 len = PTR_DIFF(p, pdata);
1640 pad = (len + (align-1)) & ~(align-1);
1642 * offset to the next entry, the caller
1643 * will overwrite it for the last entry
1644 * that's why we always include the padding
1646 SIVAL(pdata,0,pad);
1648 * set padding to zero
1650 if (do_pad) {
1651 memset(p, 0, pad - len);
1652 p = pdata + pad;
1653 } else {
1654 p = pdata + len;
1656 break;
1658 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
1659 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
1660 p += 4;
1661 SIVAL(p,0,reskey); p += 4;
1662 put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1663 put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1664 put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1665 put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1666 SOFF_T(p,0,file_size); p += 8;
1667 SOFF_T(p,0,allocation_size); p += 8;
1668 SIVAL(p,0,mode); p += 4;
1669 q = p; p += 4; /* q is placeholder for name length. */
1670 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1671 SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1672 } else {
1673 unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1674 SIVAL(p,0,ea_size); /* Extended attributes */
1676 p += 4;
1677 SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
1678 SBVAL(p,0,file_id); p += 8;
1679 status = srvstr_push(base_data, flags2, p,
1680 fname, PTR_DIFF(end_data, p),
1681 STR_TERMINATE_ASCII, &len);
1682 if (!NT_STATUS_IS_OK(status)) {
1683 return status;
1685 SIVAL(q, 0, len);
1686 p += len;
1688 len = PTR_DIFF(p, pdata);
1689 pad = (len + (align-1)) & ~(align-1);
1691 * offset to the next entry, the caller
1692 * will overwrite it for the last entry
1693 * that's why we always include the padding
1695 SIVAL(pdata,0,pad);
1697 * set padding to zero
1699 if (do_pad) {
1700 memset(p, 0, pad - len);
1701 p = pdata + pad;
1702 } else {
1703 p = pdata + len;
1705 break;
1707 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
1708 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
1709 was_8_3 = mangle_is_8_3(fname, True, conn->params);
1710 p += 4;
1711 SIVAL(p,0,reskey); p += 4;
1712 put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1713 put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1714 put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1715 put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1716 SOFF_T(p,0,file_size); p += 8;
1717 SOFF_T(p,0,allocation_size); p += 8;
1718 SIVAL(p,0,mode); p += 4;
1719 q = p; p += 4; /* q is placeholder for name length */
1720 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1721 SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1722 } else if (readdir_attr_data &&
1723 readdir_attr_data->type == RDATTR_AAPL) {
1725 * OS X specific SMB2 extension negotiated via
1726 * AAPL create context: return max_access in
1727 * ea_size field.
1729 SIVAL(p, 0, readdir_attr_data->attr_data.aapl.max_access);
1730 } else {
1731 unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1732 SIVAL(p,0,ea_size); /* Extended attributes */
1734 p += 4;
1736 if (readdir_attr_data &&
1737 readdir_attr_data->type == RDATTR_AAPL) {
1739 * OS X specific SMB2 extension negotiated via
1740 * AAPL create context: return resource fork
1741 * length and compressed FinderInfo in
1742 * shortname field.
1744 * According to documentation short_name_len
1745 * should be 0, but on the wire behaviour
1746 * shows its set to 24 by clients.
1748 SSVAL(p, 0, 24);
1750 /* Resourefork length */
1751 SBVAL(p, 2, readdir_attr_data->attr_data.aapl.rfork_size);
1753 /* Compressed FinderInfo */
1754 memcpy(p + 10, &readdir_attr_data->attr_data.aapl.finder_info, 16);
1755 } else if (!was_8_3 && check_mangled_names) {
1756 char mangled_name[13]; /* mangled 8.3 name. */
1757 if (!name_to_8_3(fname,mangled_name,True,
1758 conn->params)) {
1759 /* Error - mangle failed ! */
1760 memset(mangled_name,'\0',12);
1762 mangled_name[12] = 0;
1763 status = srvstr_push(base_data, flags2,
1764 p+2, mangled_name, 24,
1765 STR_UPPER|STR_UNICODE, &len);
1766 if (!NT_STATUS_IS_OK(status)) {
1767 return status;
1769 SSVAL(p, 0, len);
1770 if (len < 24) {
1771 memset(p + 2 + len,'\0',24 - len);
1773 SSVAL(p, 0, len);
1774 } else {
1775 /* Clear the short name buffer. This is
1776 * IMPORTANT as not doing so will trigger
1777 * a Win2k client bug. JRA.
1779 memset(p,'\0',26);
1781 p += 26;
1783 /* Reserved ? */
1784 if (readdir_attr_data &&
1785 readdir_attr_data->type == RDATTR_AAPL) {
1787 * OS X specific SMB2 extension negotiated via
1788 * AAPL create context: return UNIX mode in
1789 * reserved field.
1791 uint16_t aapl_mode = (uint16_t)readdir_attr_data->attr_data.aapl.unix_mode;
1792 SSVAL(p, 0, aapl_mode);
1793 } else {
1794 SSVAL(p, 0, 0);
1796 p += 2;
1798 SBVAL(p,0,file_id); p += 8;
1799 status = srvstr_push(base_data, flags2, p,
1800 fname, PTR_DIFF(end_data, p),
1801 STR_TERMINATE_ASCII, &len);
1802 if (!NT_STATUS_IS_OK(status)) {
1803 return status;
1805 SIVAL(q,0,len);
1806 p += len;
1808 len = PTR_DIFF(p, pdata);
1809 pad = (len + (align-1)) & ~(align-1);
1811 * offset to the next entry, the caller
1812 * will overwrite it for the last entry
1813 * that's why we always include the padding
1815 SIVAL(pdata,0,pad);
1817 * set padding to zero
1819 if (do_pad) {
1820 memset(p, 0, pad - len);
1821 p = pdata + pad;
1822 } else {
1823 p = pdata + len;
1825 break;
1827 /* CIFS UNIX Extension. */
1829 case SMB_FIND_FILE_UNIX:
1830 case SMB_FIND_FILE_UNIX_INFO2:
1831 p+= 4;
1832 SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
1834 /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
1836 if (info_level == SMB_FIND_FILE_UNIX) {
1837 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX\n"));
1838 p = store_file_unix_basic(conn, p,
1839 NULL, &smb_fname->st);
1840 status = srvstr_push(base_data, flags2, p,
1841 fname, PTR_DIFF(end_data, p),
1842 STR_TERMINATE, &len);
1843 if (!NT_STATUS_IS_OK(status)) {
1844 return status;
1846 } else {
1847 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
1848 p = store_file_unix_basic_info2(conn, p,
1849 NULL, &smb_fname->st);
1850 nameptr = p;
1851 p += 4;
1852 status = srvstr_push(base_data, flags2, p, fname,
1853 PTR_DIFF(end_data, p), 0, &len);
1854 if (!NT_STATUS_IS_OK(status)) {
1855 return status;
1857 SIVAL(nameptr, 0, len);
1860 p += len;
1862 len = PTR_DIFF(p, pdata);
1863 pad = (len + (align-1)) & ~(align-1);
1865 * offset to the next entry, the caller
1866 * will overwrite it for the last entry
1867 * that's why we always include the padding
1869 SIVAL(pdata,0,pad);
1871 * set padding to zero
1873 if (do_pad) {
1874 memset(p, 0, pad - len);
1875 p = pdata + pad;
1876 } else {
1877 p = pdata + len;
1879 /* End of SMB_QUERY_FILE_UNIX_BASIC */
1881 break;
1883 default:
1884 return NT_STATUS_INVALID_LEVEL;
1887 if (PTR_DIFF(p,pdata) > space_remaining) {
1888 DEBUG(9,("smbd_marshall_dir_entry: out of space "
1889 "(wanted %u, had %d)\n",
1890 (unsigned int)PTR_DIFF(p,pdata),
1891 space_remaining ));
1892 return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
1895 /* Setup the last entry pointer, as an offset from base_data */
1896 *last_entry_off = PTR_DIFF(last_entry_ptr,base_data);
1897 /* Advance the data pointer to the next slot */
1898 *ppdata = p;
1900 return NT_STATUS_OK;
1903 NTSTATUS smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
1904 connection_struct *conn,
1905 struct dptr_struct *dirptr,
1906 uint16_t flags2,
1907 const char *path_mask,
1908 uint32_t dirtype,
1909 int info_level,
1910 int requires_resume_key,
1911 bool dont_descend,
1912 bool ask_sharemode,
1913 bool get_dosmode,
1914 uint8_t align,
1915 bool do_pad,
1916 char **ppdata,
1917 char *base_data,
1918 char *end_data,
1919 int space_remaining,
1920 struct smb_filename **_smb_fname,
1921 bool *got_exact_match,
1922 int *_last_entry_off,
1923 struct ea_list *name_list,
1924 struct file_id *file_id)
1926 const char *p;
1927 const char *mask = NULL;
1928 long prev_dirpos = 0;
1929 uint32_t mode = 0;
1930 char *fname = NULL;
1931 struct smb_filename *smb_fname = NULL;
1932 struct smbd_dirptr_lanman2_state state;
1933 bool ok;
1934 uint64_t last_entry_off = 0;
1935 NTSTATUS status;
1936 enum mangled_names_options mangled_names;
1937 bool marshall_with_83_names;
1939 mangled_names = lp_mangled_names(conn->params);
1941 ZERO_STRUCT(state);
1942 state.conn = conn;
1943 state.info_level = info_level;
1944 if (mangled_names != MANGLED_NAMES_NO) {
1945 state.check_mangled_names = true;
1947 state.has_wild = dptr_has_wild(dirptr);
1948 state.got_exact_match = false;
1949 state.case_sensitive = dptr_case_sensitive(dirptr);
1951 *got_exact_match = false;
1953 p = strrchr_m(path_mask,'/');
1954 if(p != NULL) {
1955 if(p[1] == '\0') {
1956 mask = "*.*";
1957 } else {
1958 mask = p+1;
1960 } else {
1961 mask = path_mask;
1964 ok = smbd_dirptr_get_entry(ctx,
1965 dirptr,
1966 mask,
1967 dirtype,
1968 dont_descend,
1969 ask_sharemode,
1970 get_dosmode,
1971 smbd_dirptr_lanman2_match_fn,
1972 smbd_dirptr_lanman2_mode_fn,
1973 &state,
1974 &fname,
1975 &smb_fname,
1976 &mode,
1977 &prev_dirpos);
1978 if (!ok) {
1979 return NT_STATUS_END_OF_FILE;
1982 *got_exact_match = state.got_exact_match;
1984 marshall_with_83_names = (mangled_names == MANGLED_NAMES_YES);
1986 status = smbd_marshall_dir_entry(ctx,
1987 conn,
1988 flags2,
1989 info_level,
1990 name_list,
1991 marshall_with_83_names,
1992 requires_resume_key,
1993 mode,
1994 fname,
1995 smb_fname,
1996 space_remaining,
1997 align,
1998 do_pad,
1999 base_data,
2000 ppdata,
2001 end_data,
2002 &last_entry_off);
2003 if (NT_STATUS_EQUAL(status, NT_STATUS_ILLEGAL_CHARACTER)) {
2004 DEBUG(1,("Conversion error: illegal character: %s\n",
2005 smb_fname_str_dbg(smb_fname)));
2008 if (file_id != NULL) {
2009 *file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
2012 if (!NT_STATUS_IS_OK(status) &&
2013 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES))
2015 TALLOC_FREE(smb_fname);
2016 TALLOC_FREE(fname);
2017 return status;
2020 if (_smb_fname != NULL) {
2022 * smb_fname is already talloc'ed off ctx.
2023 * We just need to make sure we don't return
2024 * any stream_name, and replace base_name
2025 * with fname in case base_name got mangled.
2026 * This allows us to preserve any smb_fname->fsp
2027 * for asynchronous handle lookups.
2029 TALLOC_FREE(smb_fname->stream_name);
2030 TALLOC_FREE(smb_fname->base_name);
2031 smb_fname->base_name = talloc_strdup(smb_fname, fname);
2033 if (smb_fname->base_name == NULL) {
2034 TALLOC_FREE(smb_fname);
2035 TALLOC_FREE(fname);
2036 return NT_STATUS_NO_MEMORY;
2038 *_smb_fname = smb_fname;
2039 } else {
2040 TALLOC_FREE(smb_fname);
2042 TALLOC_FREE(fname);
2044 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
2045 dptr_SeekDir(dirptr, prev_dirpos);
2046 return status;
2049 *_last_entry_off = last_entry_off;
2050 return NT_STATUS_OK;
2053 unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
2055 const struct loadparm_substitution *lp_sub =
2056 loadparm_s3_global_substitution();
2058 E_md4hash(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),objid);
2059 return objid;
2062 static void samba_extended_info_version(struct smb_extended_info *extended_info)
2064 SMB_ASSERT(extended_info != NULL);
2066 extended_info->samba_magic = SAMBA_EXTENDED_INFO_MAGIC;
2067 extended_info->samba_version = ((SAMBA_VERSION_MAJOR & 0xff) << 24)
2068 | ((SAMBA_VERSION_MINOR & 0xff) << 16)
2069 | ((SAMBA_VERSION_RELEASE & 0xff) << 8);
2070 #ifdef SAMBA_VERSION_REVISION
2071 extended_info->samba_version |= (tolower(*SAMBA_VERSION_REVISION) - 'a' + 1) & 0xff;
2072 #endif
2073 extended_info->samba_subversion = 0;
2074 #ifdef SAMBA_VERSION_RC_RELEASE
2075 extended_info->samba_subversion |= (SAMBA_VERSION_RC_RELEASE & 0xff) << 24;
2076 #else
2077 #ifdef SAMBA_VERSION_PRE_RELEASE
2078 extended_info->samba_subversion |= (SAMBA_VERSION_PRE_RELEASE & 0xff) << 16;
2079 #endif
2080 #endif
2081 #ifdef SAMBA_VERSION_VENDOR_PATCH
2082 extended_info->samba_subversion |= (SAMBA_VERSION_VENDOR_PATCH & 0xffff);
2083 #endif
2084 extended_info->samba_gitcommitdate = 0;
2085 #ifdef SAMBA_VERSION_COMMIT_TIME
2086 unix_to_nt_time(&extended_info->samba_gitcommitdate, SAMBA_VERSION_COMMIT_TIME);
2087 #endif
2089 memset(extended_info->samba_version_string, 0,
2090 sizeof(extended_info->samba_version_string));
2092 snprintf (extended_info->samba_version_string,
2093 sizeof(extended_info->samba_version_string),
2094 "%s", samba_version_string());
2097 NTSTATUS smbd_do_qfsinfo(struct smbXsrv_connection *xconn,
2098 connection_struct *conn,
2099 TALLOC_CTX *mem_ctx,
2100 uint16_t info_level,
2101 uint16_t flags2,
2102 unsigned int max_data_bytes,
2103 size_t *fixed_portion,
2104 struct smb_filename *fname,
2105 char **ppdata,
2106 int *ret_data_len)
2108 const struct loadparm_substitution *lp_sub =
2109 loadparm_s3_global_substitution();
2110 char *pdata, *end_data;
2111 int data_len = 0;
2112 size_t len = 0;
2113 const char *vname = volume_label(talloc_tos(), SNUM(conn));
2114 int snum = SNUM(conn);
2115 const char *fstype = lp_fstype(SNUM(conn));
2116 const char *filename = NULL;
2117 const uint64_t bytes_per_sector = 512;
2118 uint32_t additional_flags = 0;
2119 struct smb_filename smb_fname;
2120 SMB_STRUCT_STAT st;
2121 NTSTATUS status = NT_STATUS_OK;
2122 uint64_t df_ret;
2124 if (fname == NULL || fname->base_name == NULL) {
2125 filename = ".";
2126 } else {
2127 filename = fname->base_name;
2130 if (IS_IPC(conn)) {
2131 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
2132 DEBUG(0,("smbd_do_qfsinfo: not an allowed "
2133 "info level (0x%x) on IPC$.\n",
2134 (unsigned int)info_level));
2135 return NT_STATUS_ACCESS_DENIED;
2139 DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level));
2141 smb_fname = (struct smb_filename) {
2142 .base_name = discard_const_p(char, filename),
2143 .flags = fname ? fname->flags : 0,
2144 .twrp = fname ? fname->twrp : 0,
2147 if(info_level != SMB_FS_QUOTA_INFORMATION
2148 && SMB_VFS_STAT(conn, &smb_fname) != 0) {
2149 DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
2150 return map_nt_error_from_unix(errno);
2153 st = smb_fname.st;
2155 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
2156 return NT_STATUS_INVALID_PARAMETER;
2159 *ppdata = (char *)SMB_REALLOC(
2160 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2161 if (*ppdata == NULL) {
2162 return NT_STATUS_NO_MEMORY;
2165 pdata = *ppdata;
2166 memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2167 end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2169 *fixed_portion = 0;
2171 switch (info_level) {
2172 case SMB_INFO_ALLOCATION:
2174 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
2175 data_len = 18;
2176 df_ret = get_dfree_info(conn, &smb_fname, &bsize,
2177 &dfree, &dsize);
2178 if (df_ret == (uint64_t)-1) {
2179 return map_nt_error_from_unix(errno);
2182 block_size = lp_block_size(snum);
2183 if (bsize < block_size) {
2184 uint64_t factor = block_size/bsize;
2185 bsize = block_size;
2186 dsize /= factor;
2187 dfree /= factor;
2189 if (bsize > block_size) {
2190 uint64_t factor = bsize/block_size;
2191 bsize = block_size;
2192 dsize *= factor;
2193 dfree *= factor;
2195 sectors_per_unit = bsize/bytes_per_sector;
2197 DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
2198 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
2199 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2202 * For large drives, return max values and not modulo.
2204 dsize = MIN(dsize, UINT32_MAX);
2205 dfree = MIN(dfree, UINT32_MAX);
2207 SIVAL(pdata,l1_idFileSystem,st.st_ex_dev);
2208 SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
2209 SIVAL(pdata,l1_cUnit,dsize);
2210 SIVAL(pdata,l1_cUnitAvail,dfree);
2211 SSVAL(pdata,l1_cbSector,bytes_per_sector);
2212 break;
2215 case SMB_INFO_VOLUME:
2216 /* Return volume name */
2218 * Add volume serial number - hash of a combination of
2219 * the called hostname and the service name.
2221 SIVAL(pdata,0,str_checksum(lp_servicename(talloc_tos(), lp_sub, snum)) ^ (str_checksum(get_local_machine_name())<<16) );
2223 * Win2k3 and previous mess this up by sending a name length
2224 * one byte short. I believe only older clients (OS/2 Win9x) use
2225 * this call so try fixing this by adding a terminating null to
2226 * the pushed string. The change here was adding the STR_TERMINATE. JRA.
2228 status = srvstr_push(
2229 pdata, flags2,
2230 pdata+l2_vol_szVolLabel, vname,
2231 PTR_DIFF(end_data, pdata+l2_vol_szVolLabel),
2232 STR_NOALIGN|STR_TERMINATE, &len);
2233 if (!NT_STATUS_IS_OK(status)) {
2234 return status;
2236 SCVAL(pdata,l2_vol_cch,len);
2237 data_len = l2_vol_szVolLabel + len;
2238 DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %u, name = %s\n",
2239 (unsigned)convert_timespec_to_time_t(st.st_ex_ctime),
2240 (unsigned)len, vname));
2241 break;
2243 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2244 case SMB_FS_ATTRIBUTE_INFORMATION:
2246 additional_flags = 0;
2247 #if defined(HAVE_SYS_QUOTAS)
2248 additional_flags |= FILE_VOLUME_QUOTAS;
2249 #endif
2251 if(lp_nt_acl_support(SNUM(conn))) {
2252 additional_flags |= FILE_PERSISTENT_ACLS;
2255 /* Capabilities are filled in at connection time through STATVFS call */
2256 additional_flags |= conn->fs_capabilities;
2257 additional_flags |= lp_parm_int(conn->params->service,
2258 "share", "fake_fscaps",
2261 SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
2262 FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
2263 additional_flags); /* FS ATTRIBUTES */
2265 SIVAL(pdata,4,255); /* Max filename component length */
2266 /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
2267 and will think we can't do long filenames */
2268 status = srvstr_push(pdata, flags2, pdata+12, fstype,
2269 PTR_DIFF(end_data, pdata+12),
2270 STR_UNICODE, &len);
2271 if (!NT_STATUS_IS_OK(status)) {
2272 return status;
2274 SIVAL(pdata,8,len);
2275 data_len = 12 + len;
2276 if (max_data_bytes >= 16 && data_len > max_data_bytes) {
2277 /* the client only requested a portion of the
2278 file system name */
2279 data_len = max_data_bytes;
2280 status = STATUS_BUFFER_OVERFLOW;
2282 *fixed_portion = 16;
2283 break;
2285 case SMB_QUERY_FS_LABEL_INFO:
2286 case SMB_FS_LABEL_INFORMATION:
2287 status = srvstr_push(pdata, flags2, pdata+4, vname,
2288 PTR_DIFF(end_data, pdata+4), 0, &len);
2289 if (!NT_STATUS_IS_OK(status)) {
2290 return status;
2292 data_len = 4 + len;
2293 SIVAL(pdata,0,len);
2294 break;
2296 case SMB_QUERY_FS_VOLUME_INFO:
2297 case SMB_FS_VOLUME_INFORMATION:
2300 * Add volume serial number - hash of a combination of
2301 * the called hostname and the service name.
2303 SIVAL(pdata,8,str_checksum(lp_servicename(talloc_tos(), lp_sub, snum)) ^
2304 (str_checksum(get_local_machine_name())<<16));
2306 /* Max label len is 32 characters. */
2307 status = srvstr_push(pdata, flags2, pdata+18, vname,
2308 PTR_DIFF(end_data, pdata+18),
2309 STR_UNICODE, &len);
2310 if (!NT_STATUS_IS_OK(status)) {
2311 return status;
2313 SIVAL(pdata,12,len);
2314 data_len = 18+len;
2316 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
2317 (int)strlen(vname),vname,
2318 lp_servicename(talloc_tos(), lp_sub, snum)));
2319 if (max_data_bytes >= 24 && data_len > max_data_bytes) {
2320 /* the client only requested a portion of the
2321 volume label */
2322 data_len = max_data_bytes;
2323 status = STATUS_BUFFER_OVERFLOW;
2325 *fixed_portion = 24;
2326 break;
2328 case SMB_QUERY_FS_SIZE_INFO:
2329 case SMB_FS_SIZE_INFORMATION:
2331 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
2332 data_len = 24;
2333 df_ret = get_dfree_info(conn, &smb_fname, &bsize,
2334 &dfree, &dsize);
2335 if (df_ret == (uint64_t)-1) {
2336 return map_nt_error_from_unix(errno);
2338 block_size = lp_block_size(snum);
2339 if (bsize < block_size) {
2340 uint64_t factor = block_size/bsize;
2341 bsize = block_size;
2342 dsize /= factor;
2343 dfree /= factor;
2345 if (bsize > block_size) {
2346 uint64_t factor = bsize/block_size;
2347 bsize = block_size;
2348 dsize *= factor;
2349 dfree *= factor;
2351 sectors_per_unit = bsize/bytes_per_sector;
2352 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
2353 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
2354 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2355 SBIG_UINT(pdata,0,dsize);
2356 SBIG_UINT(pdata,8,dfree);
2357 SIVAL(pdata,16,sectors_per_unit);
2358 SIVAL(pdata,20,bytes_per_sector);
2359 *fixed_portion = 24;
2360 break;
2363 case SMB_FS_FULL_SIZE_INFORMATION:
2365 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
2366 data_len = 32;
2367 df_ret = get_dfree_info(conn, &smb_fname, &bsize,
2368 &dfree, &dsize);
2369 if (df_ret == (uint64_t)-1) {
2370 return map_nt_error_from_unix(errno);
2372 block_size = lp_block_size(snum);
2373 if (bsize < block_size) {
2374 uint64_t factor = block_size/bsize;
2375 bsize = block_size;
2376 dsize /= factor;
2377 dfree /= factor;
2379 if (bsize > block_size) {
2380 uint64_t factor = bsize/block_size;
2381 bsize = block_size;
2382 dsize *= factor;
2383 dfree *= factor;
2385 sectors_per_unit = bsize/bytes_per_sector;
2386 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
2387 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
2388 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2389 SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
2390 SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
2391 SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
2392 SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
2393 SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
2394 *fixed_portion = 32;
2395 break;
2398 case SMB_QUERY_FS_DEVICE_INFO:
2399 case SMB_FS_DEVICE_INFORMATION:
2401 uint32_t characteristics = FILE_DEVICE_IS_MOUNTED;
2403 if (!CAN_WRITE(conn)) {
2404 characteristics |= FILE_READ_ONLY_DEVICE;
2406 data_len = 8;
2407 SIVAL(pdata,0,FILE_DEVICE_DISK); /* dev type */
2408 SIVAL(pdata,4,characteristics);
2409 *fixed_portion = 8;
2410 break;
2413 #ifdef HAVE_SYS_QUOTAS
2414 case SMB_FS_QUOTA_INFORMATION:
2416 * what we have to send --metze:
2418 * Unknown1: 24 NULL bytes
2419 * Soft Quota Treshold: 8 bytes seems like uint64_t or so
2420 * Hard Quota Limit: 8 bytes seems like uint64_t or so
2421 * Quota Flags: 2 byte :
2422 * Unknown3: 6 NULL bytes
2424 * 48 bytes total
2426 * details for Quota Flags:
2428 * 0x0020 Log Limit: log if the user exceeds his Hard Quota
2429 * 0x0010 Log Warn: log if the user exceeds his Soft Quota
2430 * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
2431 * 0x0001 Enable Quotas: enable quota for this fs
2435 /* we need to fake up a fsp here,
2436 * because its not send in this call
2438 files_struct fsp;
2439 SMB_NTQUOTA_STRUCT quotas;
2441 ZERO_STRUCT(fsp);
2442 ZERO_STRUCT(quotas);
2444 fsp.conn = conn;
2445 fsp.fnum = FNUM_FIELD_INVALID;
2447 /* access check */
2448 if (get_current_uid(conn) != 0) {
2449 DEBUG(0,("get_user_quota: access_denied "
2450 "service [%s] user [%s]\n",
2451 lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
2452 conn->session_info->unix_info->unix_name));
2453 return NT_STATUS_ACCESS_DENIED;
2456 status = vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE,
2457 NULL, &quotas);
2458 if (!NT_STATUS_IS_OK(status)) {
2459 DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2460 return status;
2463 data_len = 48;
2465 DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",
2466 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2468 /* Unknown1 24 NULL bytes*/
2469 SBIG_UINT(pdata,0,(uint64_t)0);
2470 SBIG_UINT(pdata,8,(uint64_t)0);
2471 SBIG_UINT(pdata,16,(uint64_t)0);
2473 /* Default Soft Quota 8 bytes */
2474 SBIG_UINT(pdata,24,quotas.softlim);
2476 /* Default Hard Quota 8 bytes */
2477 SBIG_UINT(pdata,32,quotas.hardlim);
2479 /* Quota flag 2 bytes */
2480 SSVAL(pdata,40,quotas.qflags);
2482 /* Unknown3 6 NULL bytes */
2483 SSVAL(pdata,42,0);
2484 SIVAL(pdata,44,0);
2486 break;
2488 #endif /* HAVE_SYS_QUOTAS */
2489 case SMB_FS_OBJECTID_INFORMATION:
2491 unsigned char objid[16];
2492 struct smb_extended_info extended_info;
2493 memcpy(pdata,create_volume_objectid(conn, objid),16);
2494 samba_extended_info_version (&extended_info);
2495 SIVAL(pdata,16,extended_info.samba_magic);
2496 SIVAL(pdata,20,extended_info.samba_version);
2497 SIVAL(pdata,24,extended_info.samba_subversion);
2498 SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
2499 memcpy(pdata+36,extended_info.samba_version_string,28);
2500 data_len = 64;
2501 break;
2504 case SMB_FS_SECTOR_SIZE_INFORMATION:
2506 data_len = 28;
2508 * These values match a physical Windows Server 2012
2509 * share backed by NTFS atop spinning rust.
2511 DEBUG(5, ("SMB_FS_SECTOR_SIZE_INFORMATION:"));
2512 /* logical_bytes_per_sector */
2513 SIVAL(pdata, 0, bytes_per_sector);
2514 /* phys_bytes_per_sector_atomic */
2515 SIVAL(pdata, 4, bytes_per_sector);
2516 /* phys_bytes_per_sector_perf */
2517 SIVAL(pdata, 8, bytes_per_sector);
2518 /* fs_effective_phys_bytes_per_sector_atomic */
2519 SIVAL(pdata, 12, bytes_per_sector);
2520 /* flags */
2521 SIVAL(pdata, 16, SSINFO_FLAGS_ALIGNED_DEVICE
2522 | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE);
2523 /* byte_off_sector_align */
2524 SIVAL(pdata, 20, 0);
2525 /* byte_off_partition_align */
2526 SIVAL(pdata, 24, 0);
2527 *fixed_portion = 28;
2528 break;
2532 #if defined(WITH_SMB1SERVER)
2534 * Query the version and capabilities of the CIFS UNIX extensions
2535 * in use.
2538 case SMB_QUERY_CIFS_UNIX_INFO:
2540 bool large_write = lp_min_receive_file_size() &&
2541 !smb1_srv_is_signing_active(xconn);
2542 bool large_read = !smb1_srv_is_signing_active(xconn);
2543 int encrypt_caps = 0;
2545 if (!lp_smb1_unix_extensions()) {
2546 return NT_STATUS_INVALID_LEVEL;
2549 switch (conn->encrypt_level) {
2550 case SMB_SIGNING_OFF:
2551 encrypt_caps = 0;
2552 break;
2553 case SMB_SIGNING_DESIRED:
2554 case SMB_SIGNING_IF_REQUIRED:
2555 case SMB_SIGNING_DEFAULT:
2556 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
2557 break;
2558 case SMB_SIGNING_REQUIRED:
2559 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
2560 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
2561 large_write = false;
2562 large_read = false;
2563 break;
2566 data_len = 12;
2567 SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
2568 SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
2570 /* We have POSIX ACLs, pathname, encryption,
2571 * large read/write, and locking capability. */
2573 SBIG_UINT(pdata,4,((uint64_t)(
2574 CIFS_UNIX_POSIX_ACLS_CAP|
2575 CIFS_UNIX_POSIX_PATHNAMES_CAP|
2576 CIFS_UNIX_FCNTL_LOCKS_CAP|
2577 CIFS_UNIX_EXTATTR_CAP|
2578 CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
2579 encrypt_caps|
2580 (large_read ? CIFS_UNIX_LARGE_READ_CAP : 0) |
2581 (large_write ?
2582 CIFS_UNIX_LARGE_WRITE_CAP : 0))));
2583 break;
2585 #endif
2587 case SMB_QUERY_POSIX_FS_INFO:
2589 int rc;
2590 vfs_statvfs_struct svfs;
2592 if (!lp_smb1_unix_extensions()) {
2593 return NT_STATUS_INVALID_LEVEL;
2596 rc = SMB_VFS_STATVFS(conn, &smb_fname, &svfs);
2598 if (!rc) {
2599 data_len = 56;
2600 SIVAL(pdata,0,svfs.OptimalTransferSize);
2601 SIVAL(pdata,4,svfs.BlockSize);
2602 SBIG_UINT(pdata,8,svfs.TotalBlocks);
2603 SBIG_UINT(pdata,16,svfs.BlocksAvail);
2604 SBIG_UINT(pdata,24,svfs.UserBlocksAvail);
2605 SBIG_UINT(pdata,32,svfs.TotalFileNodes);
2606 SBIG_UINT(pdata,40,svfs.FreeFileNodes);
2607 SBIG_UINT(pdata,48,svfs.FsIdentifier);
2608 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
2609 #ifdef EOPNOTSUPP
2610 } else if (rc == EOPNOTSUPP) {
2611 return NT_STATUS_INVALID_LEVEL;
2612 #endif /* EOPNOTSUPP */
2613 } else {
2614 DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2615 return NT_STATUS_DOS(ERRSRV, ERRerror);
2617 break;
2620 case SMB_QUERY_POSIX_WHOAMI:
2622 uint32_t flags = 0;
2623 uint32_t sid_bytes;
2624 uint32_t i;
2626 if (!lp_smb1_unix_extensions()) {
2627 return NT_STATUS_INVALID_LEVEL;
2630 if (max_data_bytes < 40) {
2631 return NT_STATUS_BUFFER_TOO_SMALL;
2634 if (security_session_user_level(conn->session_info, NULL) < SECURITY_USER) {
2635 flags |= SMB_WHOAMI_GUEST;
2638 /* NOTE: 8 bytes for UID/GID, irrespective of native
2639 * platform size. This matches
2640 * SMB_QUERY_FILE_UNIX_BASIC and friends.
2642 data_len = 4 /* flags */
2643 + 4 /* flag mask */
2644 + 8 /* uid */
2645 + 8 /* gid */
2646 + 4 /* ngroups */
2647 + 4 /* num_sids */
2648 + 4 /* SID bytes */
2649 + 4 /* pad/reserved */
2650 + (conn->session_info->unix_token->ngroups * 8)
2651 /* groups list */
2652 + (conn->session_info->security_token->num_sids *
2653 SID_MAX_SIZE)
2654 /* SID list */;
2656 SIVAL(pdata, 0, flags);
2657 SIVAL(pdata, 4, SMB_WHOAMI_MASK);
2658 SBIG_UINT(pdata, 8,
2659 (uint64_t)conn->session_info->unix_token->uid);
2660 SBIG_UINT(pdata, 16,
2661 (uint64_t)conn->session_info->unix_token->gid);
2664 if (data_len >= max_data_bytes) {
2665 /* Potential overflow, skip the GIDs and SIDs. */
2667 SIVAL(pdata, 24, 0); /* num_groups */
2668 SIVAL(pdata, 28, 0); /* num_sids */
2669 SIVAL(pdata, 32, 0); /* num_sid_bytes */
2670 SIVAL(pdata, 36, 0); /* reserved */
2672 data_len = 40;
2673 break;
2676 SIVAL(pdata, 24, conn->session_info->unix_token->ngroups);
2677 SIVAL(pdata, 28, conn->session_info->security_token->num_sids);
2679 /* We walk the SID list twice, but this call is fairly
2680 * infrequent, and I don't expect that it's performance
2681 * sensitive -- jpeach
2683 for (i = 0, sid_bytes = 0;
2684 i < conn->session_info->security_token->num_sids; ++i) {
2685 sid_bytes += ndr_size_dom_sid(
2686 &conn->session_info->security_token->sids[i],
2690 /* SID list byte count */
2691 SIVAL(pdata, 32, sid_bytes);
2693 /* 4 bytes pad/reserved - must be zero */
2694 SIVAL(pdata, 36, 0);
2695 data_len = 40;
2697 /* GID list */
2698 for (i = 0; i < conn->session_info->unix_token->ngroups; ++i) {
2699 SBIG_UINT(pdata, data_len,
2700 (uint64_t)conn->session_info->unix_token->groups[i]);
2701 data_len += 8;
2704 /* SID list */
2705 for (i = 0;
2706 i < conn->session_info->security_token->num_sids; ++i) {
2707 int sid_len = ndr_size_dom_sid(
2708 &conn->session_info->security_token->sids[i],
2711 sid_linearize((uint8_t *)(pdata + data_len),
2712 sid_len,
2713 &conn->session_info->security_token->sids[i]);
2714 data_len += sid_len;
2717 break;
2720 case SMB_MAC_QUERY_FS_INFO:
2722 * Thursby MAC extension... ONLY on NTFS filesystems
2723 * once we do streams then we don't need this
2725 if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
2726 data_len = 88;
2727 SIVAL(pdata,84,0x100); /* Don't support mac... */
2728 break;
2731 FALL_THROUGH;
2732 default:
2733 return NT_STATUS_INVALID_LEVEL;
2736 *ret_data_len = data_len;
2737 return status;
2740 NTSTATUS smb_set_fsquota(connection_struct *conn,
2741 struct smb_request *req,
2742 files_struct *fsp,
2743 const DATA_BLOB *qdata)
2745 const struct loadparm_substitution *lp_sub =
2746 loadparm_s3_global_substitution();
2747 NTSTATUS status;
2748 SMB_NTQUOTA_STRUCT quotas;
2750 ZERO_STRUCT(quotas);
2752 /* access check */
2753 if ((get_current_uid(conn) != 0) || !CAN_WRITE(conn)) {
2754 DEBUG(3, ("set_fsquota: access_denied service [%s] user [%s]\n",
2755 lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
2756 conn->session_info->unix_info->unix_name));
2757 return NT_STATUS_ACCESS_DENIED;
2760 if (!check_fsp_ntquota_handle(conn, req,
2761 fsp)) {
2762 DEBUG(1, ("set_fsquota: no valid QUOTA HANDLE\n"));
2763 return NT_STATUS_INVALID_HANDLE;
2766 /* note: normally there're 48 bytes,
2767 * but we didn't use the last 6 bytes for now
2768 * --metze
2770 if (qdata->length < 42) {
2771 DEBUG(0,("set_fsquota: requires total_data(%u) >= 42 bytes!\n",
2772 (unsigned int)qdata->length));
2773 return NT_STATUS_INVALID_PARAMETER;
2776 /* unknown_1 24 NULL bytes in pdata*/
2778 /* the soft quotas 8 bytes (uint64_t)*/
2779 quotas.softlim = BVAL(qdata->data,24);
2781 /* the hard quotas 8 bytes (uint64_t)*/
2782 quotas.hardlim = BVAL(qdata->data,32);
2784 /* quota_flags 2 bytes **/
2785 quotas.qflags = SVAL(qdata->data,40);
2787 /* unknown_2 6 NULL bytes follow*/
2789 /* now set the quotas */
2790 if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
2791 DEBUG(1, ("vfs_set_ntquota() failed for service [%s]\n",
2792 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2793 status = map_nt_error_from_unix(errno);
2794 } else {
2795 status = NT_STATUS_OK;
2797 return status;
2800 NTSTATUS smbd_do_setfsinfo(connection_struct *conn,
2801 struct smb_request *req,
2802 TALLOC_CTX *mem_ctx,
2803 uint16_t info_level,
2804 files_struct *fsp,
2805 const DATA_BLOB *pdata)
2807 switch (info_level) {
2808 case SMB_FS_QUOTA_INFORMATION:
2810 return smb_set_fsquota(conn,
2811 req,
2812 fsp,
2813 pdata);
2816 default:
2817 break;
2819 return NT_STATUS_INVALID_LEVEL;
2822 #if defined(HAVE_POSIX_ACLS)
2823 /****************************************************************************
2824 Utility function to count the number of entries in a POSIX acl.
2825 ****************************************************************************/
2827 static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
2829 unsigned int ace_count = 0;
2830 int entry_id = SMB_ACL_FIRST_ENTRY;
2831 SMB_ACL_ENTRY_T entry;
2833 while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2834 /* get_next... */
2835 if (entry_id == SMB_ACL_FIRST_ENTRY) {
2836 entry_id = SMB_ACL_NEXT_ENTRY;
2838 ace_count++;
2840 return ace_count;
2843 /****************************************************************************
2844 Utility function to marshall a POSIX acl into wire format.
2845 ****************************************************************************/
2847 static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
2849 int entry_id = SMB_ACL_FIRST_ENTRY;
2850 SMB_ACL_ENTRY_T entry;
2852 while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2853 SMB_ACL_TAG_T tagtype;
2854 SMB_ACL_PERMSET_T permset;
2855 unsigned char perms = 0;
2856 unsigned int own_grp;
2858 /* get_next... */
2859 if (entry_id == SMB_ACL_FIRST_ENTRY) {
2860 entry_id = SMB_ACL_NEXT_ENTRY;
2863 if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
2864 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
2865 return False;
2868 if (sys_acl_get_permset(entry, &permset) == -1) {
2869 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
2870 return False;
2873 perms |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
2874 perms |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
2875 perms |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
2877 SCVAL(pdata,1,perms);
2879 switch (tagtype) {
2880 case SMB_ACL_USER_OBJ:
2881 SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
2882 own_grp = (unsigned int)pst->st_ex_uid;
2883 SIVAL(pdata,2,own_grp);
2884 SIVAL(pdata,6,0);
2885 break;
2886 case SMB_ACL_USER:
2888 uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
2889 if (!puid) {
2890 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2891 return False;
2893 own_grp = (unsigned int)*puid;
2894 SCVAL(pdata,0,SMB_POSIX_ACL_USER);
2895 SIVAL(pdata,2,own_grp);
2896 SIVAL(pdata,6,0);
2897 break;
2899 case SMB_ACL_GROUP_OBJ:
2900 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
2901 own_grp = (unsigned int)pst->st_ex_gid;
2902 SIVAL(pdata,2,own_grp);
2903 SIVAL(pdata,6,0);
2904 break;
2905 case SMB_ACL_GROUP:
2907 gid_t *pgid= (gid_t *)sys_acl_get_qualifier(entry);
2908 if (!pgid) {
2909 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2910 return False;
2912 own_grp = (unsigned int)*pgid;
2913 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
2914 SIVAL(pdata,2,own_grp);
2915 SIVAL(pdata,6,0);
2916 break;
2918 case SMB_ACL_MASK:
2919 SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
2920 SIVAL(pdata,2,0xFFFFFFFF);
2921 SIVAL(pdata,6,0xFFFFFFFF);
2922 break;
2923 case SMB_ACL_OTHER:
2924 SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
2925 SIVAL(pdata,2,0xFFFFFFFF);
2926 SIVAL(pdata,6,0xFFFFFFFF);
2927 break;
2928 default:
2929 DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
2930 return False;
2932 pdata += SMB_POSIX_ACL_ENTRY_SIZE;
2935 return True;
2937 #endif
2939 /****************************************************************************
2940 Store the FILE_UNIX_BASIC info.
2941 ****************************************************************************/
2943 static char *store_file_unix_basic(connection_struct *conn,
2944 char *pdata,
2945 files_struct *fsp,
2946 const SMB_STRUCT_STAT *psbuf)
2948 dev_t devno;
2950 DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
2951 DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode));
2953 SOFF_T(pdata,0,get_file_size_stat(psbuf)); /* File size 64 Bit */
2954 pdata += 8;
2956 SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
2957 pdata += 8;
2959 put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, &psbuf->st_ex_ctime); /* Change Time 64 Bit */
2960 put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, &psbuf->st_ex_atime); /* Last access time 64 Bit */
2961 put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, &psbuf->st_ex_mtime); /* Last modification time 64 Bit */
2962 pdata += 24;
2964 SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */
2965 SIVAL(pdata,4,0);
2966 pdata += 8;
2968 SIVAL(pdata,0,psbuf->st_ex_gid); /* group id of owner */
2969 SIVAL(pdata,4,0);
2970 pdata += 8;
2972 SIVAL(pdata,0,unix_filetype(psbuf->st_ex_mode));
2973 pdata += 4;
2975 if (S_ISBLK(psbuf->st_ex_mode) || S_ISCHR(psbuf->st_ex_mode)) {
2976 devno = psbuf->st_ex_rdev;
2977 } else {
2978 devno = psbuf->st_ex_dev;
2981 SIVAL(pdata,0,unix_dev_major(devno)); /* Major device number if type is device */
2982 SIVAL(pdata,4,0);
2983 pdata += 8;
2985 SIVAL(pdata,0,unix_dev_minor(devno)); /* Minor device number if type is device */
2986 SIVAL(pdata,4,0);
2987 pdata += 8;
2989 SINO_T_VAL(pdata, 0, psbuf->st_ex_ino); /* inode number */
2990 pdata += 8;
2992 SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode)); /* Standard UNIX file permissions */
2993 SIVAL(pdata,4,0);
2994 pdata += 8;
2996 SIVAL(pdata,0,psbuf->st_ex_nlink); /* number of hard links */
2997 SIVAL(pdata,4,0);
2998 pdata += 8;
3000 return pdata;
3003 /* Forward and reverse mappings from the UNIX_INFO2 file flags field and
3004 * the chflags(2) (or equivalent) flags.
3006 * XXX: this really should be behind the VFS interface. To do this, we would
3007 * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field.
3008 * Each VFS module could then implement its own mapping as appropriate for the
3009 * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS.
3011 static const struct {unsigned stat_fflag; unsigned smb_fflag;}
3012 info2_flags_map[] =
3014 #ifdef UF_NODUMP
3015 { UF_NODUMP, EXT_DO_NOT_BACKUP },
3016 #endif
3018 #ifdef UF_IMMUTABLE
3019 { UF_IMMUTABLE, EXT_IMMUTABLE },
3020 #endif
3022 #ifdef UF_APPEND
3023 { UF_APPEND, EXT_OPEN_APPEND_ONLY },
3024 #endif
3026 #ifdef UF_HIDDEN
3027 { UF_HIDDEN, EXT_HIDDEN },
3028 #endif
3030 /* Do not remove. We need to guarantee that this array has at least one
3031 * entry to build on HP-UX.
3033 { 0, 0 }
3037 static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
3038 uint32_t *smb_fflags, uint32_t *smb_fmask)
3040 size_t i;
3042 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3043 *smb_fmask |= info2_flags_map[i].smb_fflag;
3044 if (psbuf->st_ex_flags & info2_flags_map[i].stat_fflag) {
3045 *smb_fflags |= info2_flags_map[i].smb_fflag;
3050 static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
3051 const uint32_t smb_fflags,
3052 const uint32_t smb_fmask,
3053 int *stat_fflags)
3055 uint32_t max_fmask = 0;
3056 size_t i;
3058 *stat_fflags = psbuf->st_ex_flags;
3060 /* For each flags requested in smb_fmask, check the state of the
3061 * corresponding flag in smb_fflags and set or clear the matching
3062 * stat flag.
3065 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3066 max_fmask |= info2_flags_map[i].smb_fflag;
3067 if (smb_fmask & info2_flags_map[i].smb_fflag) {
3068 if (smb_fflags & info2_flags_map[i].smb_fflag) {
3069 *stat_fflags |= info2_flags_map[i].stat_fflag;
3070 } else {
3071 *stat_fflags &= ~info2_flags_map[i].stat_fflag;
3076 /* If smb_fmask is asking to set any bits that are not supported by
3077 * our flag mappings, we should fail.
3079 if ((smb_fmask & max_fmask) != smb_fmask) {
3080 return False;
3083 return True;
3087 /* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition
3088 * of file flags and birth (create) time.
3090 static char *store_file_unix_basic_info2(connection_struct *conn,
3091 char *pdata,
3092 files_struct *fsp,
3093 const SMB_STRUCT_STAT *psbuf)
3095 uint32_t file_flags = 0;
3096 uint32_t flags_mask = 0;
3098 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
3100 /* Create (birth) time 64 bit */
3101 put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, &psbuf->st_ex_btime);
3102 pdata += 8;
3104 map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
3105 SIVAL(pdata, 0, file_flags); /* flags */
3106 SIVAL(pdata, 4, flags_mask); /* mask */
3107 pdata += 8;
3109 return pdata;
3112 static NTSTATUS marshall_stream_info(unsigned int num_streams,
3113 const struct stream_struct *streams,
3114 char *data,
3115 unsigned int max_data_bytes,
3116 unsigned int *data_size)
3118 unsigned int i;
3119 unsigned int ofs = 0;
3121 if (max_data_bytes < 32) {
3122 return NT_STATUS_INFO_LENGTH_MISMATCH;
3125 for (i = 0; i < num_streams; i++) {
3126 unsigned int next_offset;
3127 size_t namelen;
3128 smb_ucs2_t *namebuf;
3130 if (!push_ucs2_talloc(talloc_tos(), &namebuf,
3131 streams[i].name, &namelen) ||
3132 namelen <= 2)
3134 return NT_STATUS_INVALID_PARAMETER;
3138 * name_buf is now null-terminated, we need to marshall as not
3139 * terminated
3142 namelen -= 2;
3145 * We cannot overflow ...
3147 if ((ofs + 24 + namelen) > max_data_bytes) {
3148 DEBUG(10, ("refusing to overflow reply at stream %u\n",
3149 i));
3150 TALLOC_FREE(namebuf);
3151 return STATUS_BUFFER_OVERFLOW;
3154 SIVAL(data, ofs+4, namelen);
3155 SOFF_T(data, ofs+8, streams[i].size);
3156 SOFF_T(data, ofs+16, streams[i].alloc_size);
3157 memcpy(data+ofs+24, namebuf, namelen);
3158 TALLOC_FREE(namebuf);
3160 next_offset = ofs + 24 + namelen;
3162 if (i == num_streams-1) {
3163 SIVAL(data, ofs, 0);
3165 else {
3166 unsigned int align = ndr_align_size(next_offset, 8);
3168 if ((next_offset + align) > max_data_bytes) {
3169 DEBUG(10, ("refusing to overflow align "
3170 "reply at stream %u\n",
3171 i));
3172 TALLOC_FREE(namebuf);
3173 return STATUS_BUFFER_OVERFLOW;
3176 memset(data+next_offset, 0, align);
3177 next_offset += align;
3179 SIVAL(data, ofs, next_offset - ofs);
3180 ofs = next_offset;
3183 ofs = next_offset;
3186 DEBUG(10, ("max_data: %u, data_size: %u\n", max_data_bytes, ofs));
3188 *data_size = ofs;
3190 return NT_STATUS_OK;
3193 static NTSTATUS smb_unix_read_symlink(connection_struct *conn,
3194 struct smb_request *req,
3195 struct smb_filename *smb_fname,
3196 char *pdata,
3197 unsigned int data_size_in,
3198 unsigned int *pdata_size_out)
3200 NTSTATUS status;
3201 size_t len = 0;
3202 int link_len = 0;
3203 struct smb_filename *parent_fname = NULL;
3204 struct smb_filename *base_name = NULL;
3206 char *buffer = talloc_array(talloc_tos(), char, PATH_MAX+1);
3208 if (!buffer) {
3209 return NT_STATUS_NO_MEMORY;
3212 DBG_DEBUG("SMB_QUERY_FILE_UNIX_LINK for file %s\n",
3213 smb_fname_str_dbg(smb_fname));
3215 if(!S_ISLNK(smb_fname->st.st_ex_mode)) {
3216 TALLOC_FREE(buffer);
3217 return NT_STATUS_DOS(ERRSRV, ERRbadlink);
3220 status = parent_pathref(talloc_tos(),
3221 conn->cwd_fsp,
3222 smb_fname,
3223 &parent_fname,
3224 &base_name);
3225 if (!NT_STATUS_IS_OK(status)) {
3226 TALLOC_FREE(buffer);
3227 return status;
3230 link_len = SMB_VFS_READLINKAT(conn,
3231 parent_fname->fsp,
3232 base_name,
3233 buffer,
3234 PATH_MAX);
3236 TALLOC_FREE(parent_fname);
3238 if (link_len == -1) {
3239 TALLOC_FREE(buffer);
3240 return map_nt_error_from_unix(errno);
3243 buffer[link_len] = 0;
3244 status = srvstr_push(pdata,
3245 req->flags2,
3246 pdata,
3247 buffer,
3248 data_size_in,
3249 STR_TERMINATE,
3250 &len);
3251 TALLOC_FREE(buffer);
3252 if (!NT_STATUS_IS_OK(status)) {
3253 return status;
3255 *pdata_size_out = len;
3257 return NT_STATUS_OK;
3260 #if defined(HAVE_POSIX_ACLS)
3261 static NTSTATUS smb_query_posix_acl(connection_struct *conn,
3262 struct smb_request *req,
3263 files_struct *fsp,
3264 struct smb_filename *smb_fname,
3265 char *pdata,
3266 unsigned int data_size_in,
3267 unsigned int *pdata_size_out)
3269 SMB_ACL_T file_acl = NULL;
3270 SMB_ACL_T def_acl = NULL;
3271 uint16_t num_file_acls = 0;
3272 uint16_t num_def_acls = 0;
3273 unsigned int size_needed = 0;
3274 NTSTATUS status;
3275 bool ok;
3276 bool close_fsp = false;
3279 * Ensure we always operate on a file descriptor, not just
3280 * the filename.
3282 if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
3283 uint32_t access_mask = SEC_STD_READ_CONTROL|
3284 FILE_READ_ATTRIBUTES|
3285 FILE_WRITE_ATTRIBUTES;
3287 status = get_posix_fsp(conn,
3288 req,
3289 smb_fname,
3290 access_mask,
3291 &fsp);
3293 if (!NT_STATUS_IS_OK(status)) {
3294 goto out;
3296 close_fsp = true;
3299 SMB_ASSERT(fsp != NULL);
3301 status = refuse_symlink_fsp(fsp);
3302 if (!NT_STATUS_IS_OK(status)) {
3303 goto out;
3306 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, SMB_ACL_TYPE_ACCESS,
3307 talloc_tos());
3309 if (file_acl == NULL && no_acl_syscall_error(errno)) {
3310 DBG_INFO("ACLs not implemented on "
3311 "filesystem containing %s\n",
3312 fsp_str_dbg(fsp));
3313 status = NT_STATUS_NOT_IMPLEMENTED;
3314 goto out;
3317 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
3319 * We can only have default POSIX ACLs on
3320 * directories.
3322 if (!fsp->fsp_flags.is_directory) {
3323 DBG_INFO("Non-directory open %s\n",
3324 fsp_str_dbg(fsp));
3325 status = NT_STATUS_INVALID_HANDLE;
3326 goto out;
3328 def_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
3329 SMB_ACL_TYPE_DEFAULT,
3330 talloc_tos());
3331 def_acl = free_empty_sys_acl(conn, def_acl);
3334 num_file_acls = count_acl_entries(conn, file_acl);
3335 num_def_acls = count_acl_entries(conn, def_acl);
3337 /* Wrap checks. */
3338 if (num_file_acls + num_def_acls < num_file_acls) {
3339 status = NT_STATUS_INVALID_PARAMETER;
3340 goto out;
3343 size_needed = num_file_acls + num_def_acls;
3346 * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
3347 * than UINT_MAX, so check by division.
3349 if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
3350 status = NT_STATUS_INVALID_PARAMETER;
3351 goto out;
3354 size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
3355 if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
3356 status = NT_STATUS_INVALID_PARAMETER;
3357 goto out;
3359 size_needed += SMB_POSIX_ACL_HEADER_SIZE;
3361 if ( data_size_in < size_needed) {
3362 DBG_INFO("data_size too small (%u) need %u\n",
3363 data_size_in,
3364 size_needed);
3365 status = NT_STATUS_BUFFER_TOO_SMALL;
3366 goto out;
3369 SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
3370 SSVAL(pdata,2,num_file_acls);
3371 SSVAL(pdata,4,num_def_acls);
3372 pdata += SMB_POSIX_ACL_HEADER_SIZE;
3374 ok = marshall_posix_acl(conn,
3375 pdata,
3376 &fsp->fsp_name->st,
3377 file_acl);
3378 if (!ok) {
3379 status = NT_STATUS_INTERNAL_ERROR;
3380 goto out;
3382 pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
3384 ok = marshall_posix_acl(conn,
3385 pdata,
3386 &fsp->fsp_name->st,
3387 def_acl);
3388 if (!ok) {
3389 status = NT_STATUS_INTERNAL_ERROR;
3390 goto out;
3393 *pdata_size_out = size_needed;
3394 status = NT_STATUS_OK;
3396 out:
3398 if (close_fsp) {
3400 * Ensure the stat struct in smb_fname is up to
3401 * date. Structure copy.
3403 smb_fname->st = fsp->fsp_name->st;
3404 (void)close_file_free(req, &fsp, NORMAL_CLOSE);
3407 TALLOC_FREE(file_acl);
3408 TALLOC_FREE(def_acl);
3409 return status;
3411 #endif
3413 NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
3414 TALLOC_CTX *mem_ctx,
3415 struct smb_request *req,
3416 uint16_t info_level,
3417 files_struct *fsp,
3418 struct smb_filename *smb_fname,
3419 bool delete_pending,
3420 struct timespec write_time_ts,
3421 struct ea_list *ea_list,
3422 int lock_data_count,
3423 char *lock_data,
3424 uint16_t flags2,
3425 unsigned int max_data_bytes,
3426 size_t *fixed_portion,
3427 char **ppdata,
3428 unsigned int *pdata_size)
3430 char *pdata = *ppdata;
3431 char *dstart, *dend;
3432 unsigned int data_size;
3433 struct timespec create_time_ts, mtime_ts, atime_ts, ctime_ts;
3434 time_t create_time, mtime, atime, c_time;
3435 SMB_STRUCT_STAT *psbuf = NULL;
3436 SMB_STRUCT_STAT *base_sp = NULL;
3437 char *p;
3438 char *base_name;
3439 char *dos_fname;
3440 int mode;
3441 int nlink;
3442 NTSTATUS status;
3443 uint64_t file_size = 0;
3444 uint64_t pos = 0;
3445 uint64_t allocation_size = 0;
3446 uint64_t file_id = 0;
3447 uint32_t access_mask = 0;
3448 size_t len = 0;
3450 if (INFO_LEVEL_IS_UNIX(info_level)) {
3451 if (!lp_smb1_unix_extensions()) {
3452 return NT_STATUS_INVALID_LEVEL;
3454 if (!req->posix_pathnames) {
3455 return NT_STATUS_INVALID_LEVEL;
3459 DEBUG(5,("smbd_do_qfilepathinfo: %s (%s) level=%d max_data=%u\n",
3460 smb_fname_str_dbg(smb_fname),
3461 fsp_fnum_dbg(fsp),
3462 info_level, max_data_bytes));
3465 * In case of querying a symlink in POSIX context,
3466 * fsp will be NULL. fdos_mode() deals with it.
3468 if (fsp != NULL) {
3469 smb_fname = fsp->fsp_name;
3471 mode = fdos_mode(fsp);
3472 psbuf = &smb_fname->st;
3474 if (fsp != NULL) {
3475 base_sp = fsp->base_fsp ?
3476 &fsp->base_fsp->fsp_name->st :
3477 &fsp->fsp_name->st;
3478 } else {
3479 base_sp = &smb_fname->st;
3482 nlink = psbuf->st_ex_nlink;
3484 if (nlink && (mode&FILE_ATTRIBUTE_DIRECTORY)) {
3485 nlink = 1;
3488 if ((nlink > 0) && delete_pending) {
3489 nlink -= 1;
3492 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
3493 return NT_STATUS_INVALID_PARAMETER;
3496 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
3497 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
3498 if (*ppdata == NULL) {
3499 return NT_STATUS_NO_MEMORY;
3501 pdata = *ppdata;
3502 dstart = pdata;
3503 dend = dstart + data_size - 1;
3505 if (!is_omit_timespec(&write_time_ts) &&
3506 !INFO_LEVEL_IS_UNIX(info_level))
3508 update_stat_ex_mtime(psbuf, write_time_ts);
3511 create_time_ts = get_create_timespec(conn, fsp, smb_fname);
3512 mtime_ts = psbuf->st_ex_mtime;
3513 atime_ts = psbuf->st_ex_atime;
3514 ctime_ts = get_change_timespec(conn, fsp, smb_fname);
3516 if (lp_dos_filetime_resolution(SNUM(conn))) {
3517 dos_filetime_timespec(&create_time_ts);
3518 dos_filetime_timespec(&mtime_ts);
3519 dos_filetime_timespec(&atime_ts);
3520 dos_filetime_timespec(&ctime_ts);
3523 create_time = convert_timespec_to_time_t(create_time_ts);
3524 mtime = convert_timespec_to_time_t(mtime_ts);
3525 atime = convert_timespec_to_time_t(atime_ts);
3526 c_time = convert_timespec_to_time_t(ctime_ts);
3528 p = strrchr_m(smb_fname->base_name,'/');
3529 if (!p)
3530 base_name = smb_fname->base_name;
3531 else
3532 base_name = p+1;
3534 /* NT expects the name to be in an exact form of the *full*
3535 filename. See the trans2 torture test */
3536 if (ISDOT(base_name)) {
3537 dos_fname = talloc_strdup(mem_ctx, "\\");
3538 if (!dos_fname) {
3539 return NT_STATUS_NO_MEMORY;
3541 } else {
3542 dos_fname = talloc_asprintf(mem_ctx,
3543 "\\%s",
3544 smb_fname->base_name);
3545 if (!dos_fname) {
3546 return NT_STATUS_NO_MEMORY;
3548 if (is_named_stream(smb_fname)) {
3549 dos_fname = talloc_asprintf(dos_fname, "%s",
3550 smb_fname->stream_name);
3551 if (!dos_fname) {
3552 return NT_STATUS_NO_MEMORY;
3556 string_replace(dos_fname, '/', '\\');
3559 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, psbuf);
3561 if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
3562 /* Do we have this path open ? */
3563 files_struct *fsp1;
3564 struct file_id fileid = vfs_file_id_from_sbuf(conn, psbuf);
3565 fsp1 = file_find_di_first(conn->sconn, fileid, true);
3566 if (fsp1 && fsp1->initial_allocation_size) {
3567 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, psbuf);
3571 if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) {
3572 file_size = get_file_size_stat(psbuf);
3575 if (fsp) {
3576 pos = fh_get_position_information(fsp->fh);
3579 if (fsp) {
3580 access_mask = fsp->access_mask;
3581 } else {
3582 /* GENERIC_EXECUTE mapping from Windows */
3583 access_mask = 0x12019F;
3586 /* This should be an index number - looks like
3587 dev/ino to me :-)
3589 I think this causes us to fail the IFSKIT
3590 BasicFileInformationTest. -tpot */
3591 file_id = SMB_VFS_FS_FILE_ID(conn, base_sp);
3593 *fixed_portion = 0;
3595 switch (info_level) {
3596 case SMB_INFO_STANDARD:
3597 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
3598 data_size = 22;
3599 srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
3600 srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
3601 srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
3602 SIVAL(pdata,l1_cbFile,(uint32_t)file_size);
3603 SIVAL(pdata,l1_cbFileAlloc,(uint32_t)allocation_size);
3604 SSVAL(pdata,l1_attrFile,mode);
3605 break;
3607 case SMB_INFO_QUERY_EA_SIZE:
3609 unsigned int ea_size =
3610 estimate_ea_size(smb_fname->fsp);
3611 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
3612 data_size = 26;
3613 srv_put_dos_date2(pdata,0,create_time);
3614 srv_put_dos_date2(pdata,4,atime);
3615 srv_put_dos_date2(pdata,8,mtime); /* write time */
3616 SIVAL(pdata,12,(uint32_t)file_size);
3617 SIVAL(pdata,16,(uint32_t)allocation_size);
3618 SSVAL(pdata,20,mode);
3619 SIVAL(pdata,22,ea_size);
3620 break;
3623 case SMB_INFO_IS_NAME_VALID:
3624 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
3625 if (fsp) {
3626 /* os/2 needs this ? really ?*/
3627 return NT_STATUS_DOS(ERRDOS, ERRbadfunc);
3629 /* This is only reached for qpathinfo */
3630 data_size = 0;
3631 break;
3633 case SMB_INFO_QUERY_EAS_FROM_LIST:
3635 size_t total_ea_len = 0;
3636 struct ea_list *ea_file_list = NULL;
3637 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
3639 status =
3640 get_ea_list_from_fsp(mem_ctx,
3641 smb_fname->fsp,
3642 &total_ea_len, &ea_file_list);
3643 if (!NT_STATUS_IS_OK(status)) {
3644 return status;
3647 ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
3649 if (!ea_list || (total_ea_len > data_size)) {
3650 data_size = 4;
3651 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
3652 break;
3655 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
3656 break;
3659 case SMB_INFO_QUERY_ALL_EAS:
3661 /* We have data_size bytes to put EA's into. */
3662 size_t total_ea_len = 0;
3663 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
3665 status = get_ea_list_from_fsp(mem_ctx,
3666 smb_fname->fsp,
3667 &total_ea_len, &ea_list);
3668 if (!NT_STATUS_IS_OK(status)) {
3669 return status;
3672 if (!ea_list || (total_ea_len > data_size)) {
3673 data_size = 4;
3674 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
3675 break;
3678 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
3679 break;
3682 case SMB2_FILE_FULL_EA_INFORMATION:
3684 /* We have data_size bytes to put EA's into. */
3685 size_t total_ea_len = 0;
3686 struct ea_list *ea_file_list = NULL;
3688 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n"));
3690 /*TODO: add filtering and index handling */
3692 status =
3693 get_ea_list_from_fsp(mem_ctx,
3694 smb_fname->fsp,
3695 &total_ea_len, &ea_file_list);
3696 if (!NT_STATUS_IS_OK(status)) {
3697 return status;
3699 if (!ea_file_list) {
3700 return NT_STATUS_NO_EAS_ON_FILE;
3703 status = fill_ea_chained_buffer(mem_ctx,
3704 pdata,
3705 data_size,
3706 &data_size,
3707 conn, ea_file_list);
3708 if (!NT_STATUS_IS_OK(status)) {
3709 return status;
3711 break;
3714 case SMB_FILE_BASIC_INFORMATION:
3715 case SMB_QUERY_FILE_BASIC_INFO:
3717 if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
3718 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
3719 data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
3720 } else {
3721 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
3722 data_size = 40;
3723 SIVAL(pdata,36,0);
3725 put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
3726 put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
3727 put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
3728 put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
3729 SIVAL(pdata,32,mode);
3731 DEBUG(5,("SMB_QFBI - "));
3732 DEBUG(5,("create: %s ", ctime(&create_time)));
3733 DEBUG(5,("access: %s ", ctime(&atime)));
3734 DEBUG(5,("write: %s ", ctime(&mtime)));
3735 DEBUG(5,("change: %s ", ctime(&c_time)));
3736 DEBUG(5,("mode: %x\n", mode));
3737 *fixed_portion = data_size;
3738 break;
3740 case SMB_FILE_STANDARD_INFORMATION:
3741 case SMB_QUERY_FILE_STANDARD_INFO:
3743 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
3744 data_size = 24;
3745 SOFF_T(pdata,0,allocation_size);
3746 SOFF_T(pdata,8,file_size);
3747 SIVAL(pdata,16,nlink);
3748 SCVAL(pdata,20,delete_pending?1:0);
3749 SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
3750 SSVAL(pdata,22,0); /* Padding. */
3751 *fixed_portion = 24;
3752 break;
3754 case SMB_FILE_EA_INFORMATION:
3755 case SMB_QUERY_FILE_EA_INFO:
3757 unsigned int ea_size =
3758 estimate_ea_size(smb_fname->fsp);
3759 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
3760 data_size = 4;
3761 *fixed_portion = 4;
3762 SIVAL(pdata,0,ea_size);
3763 break;
3766 /* Get the 8.3 name - used if NT SMB was negotiated. */
3767 case SMB_QUERY_FILE_ALT_NAME_INFO:
3768 case SMB_FILE_ALTERNATE_NAME_INFORMATION:
3770 char mangled_name[13];
3771 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
3772 if (!name_to_8_3(base_name,mangled_name,
3773 True,conn->params)) {
3774 return NT_STATUS_NO_MEMORY;
3776 status = srvstr_push(dstart, flags2,
3777 pdata+4, mangled_name,
3778 PTR_DIFF(dend, pdata+4),
3779 STR_UNICODE, &len);
3780 if (!NT_STATUS_IS_OK(status)) {
3781 return status;
3783 data_size = 4 + len;
3784 SIVAL(pdata,0,len);
3785 *fixed_portion = 8;
3786 break;
3789 case SMB_QUERY_FILE_NAME_INFO:
3792 this must be *exactly* right for ACLs on mapped drives to work
3794 status = srvstr_push(dstart, flags2,
3795 pdata+4, dos_fname,
3796 PTR_DIFF(dend, pdata+4),
3797 STR_UNICODE, &len);
3798 if (!NT_STATUS_IS_OK(status)) {
3799 return status;
3801 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
3802 data_size = 4 + len;
3803 SIVAL(pdata,0,len);
3804 break;
3807 case SMB_FILE_NORMALIZED_NAME_INFORMATION:
3809 char *nfname = NULL;
3811 if (fsp == NULL || !fsp->conn->sconn->using_smb2) {
3812 return NT_STATUS_INVALID_LEVEL;
3815 nfname = talloc_strdup(mem_ctx, smb_fname->base_name);
3816 if (nfname == NULL) {
3817 return NT_STATUS_NO_MEMORY;
3820 if (ISDOT(nfname)) {
3821 nfname[0] = '\0';
3823 string_replace(nfname, '/', '\\');
3825 if (fsp_is_alternate_stream(fsp)) {
3826 const char *s = smb_fname->stream_name;
3827 const char *e = NULL;
3828 size_t n;
3830 SMB_ASSERT(s[0] != '\0');
3833 * smb_fname->stream_name is in form
3834 * of ':StrEam:$DATA', but we should only
3835 * append ':StrEam' here.
3838 e = strchr(&s[1], ':');
3839 if (e == NULL) {
3840 n = strlen(s);
3841 } else {
3842 n = PTR_DIFF(e, s);
3844 nfname = talloc_strndup_append(nfname, s, n);
3845 if (nfname == NULL) {
3846 return NT_STATUS_NO_MEMORY;
3850 status = srvstr_push(dstart, flags2,
3851 pdata+4, nfname,
3852 PTR_DIFF(dend, pdata+4),
3853 STR_UNICODE, &len);
3854 if (!NT_STATUS_IS_OK(status)) {
3855 return status;
3857 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NORMALIZED_NAME_INFORMATION\n"));
3858 data_size = 4 + len;
3859 SIVAL(pdata,0,len);
3860 *fixed_portion = 8;
3861 break;
3864 case SMB_FILE_ALLOCATION_INFORMATION:
3865 case SMB_QUERY_FILE_ALLOCATION_INFO:
3866 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
3867 data_size = 8;
3868 SOFF_T(pdata,0,allocation_size);
3869 break;
3871 case SMB_FILE_END_OF_FILE_INFORMATION:
3872 case SMB_QUERY_FILE_END_OF_FILEINFO:
3873 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
3874 data_size = 8;
3875 SOFF_T(pdata,0,file_size);
3876 break;
3878 case SMB_QUERY_FILE_ALL_INFO:
3879 case SMB_FILE_ALL_INFORMATION:
3881 unsigned int ea_size =
3882 estimate_ea_size(smb_fname->fsp);
3883 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
3884 put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
3885 put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
3886 put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
3887 put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
3888 SIVAL(pdata,32,mode);
3889 SIVAL(pdata,36,0); /* padding. */
3890 pdata += 40;
3891 SOFF_T(pdata,0,allocation_size);
3892 SOFF_T(pdata,8,file_size);
3893 SIVAL(pdata,16,nlink);
3894 SCVAL(pdata,20,delete_pending);
3895 SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
3896 SSVAL(pdata,22,0);
3897 pdata += 24;
3898 SIVAL(pdata,0,ea_size);
3899 pdata += 4; /* EA info */
3900 status = srvstr_push(dstart, flags2,
3901 pdata+4, dos_fname,
3902 PTR_DIFF(dend, pdata+4),
3903 STR_UNICODE, &len);
3904 if (!NT_STATUS_IS_OK(status)) {
3905 return status;
3907 SIVAL(pdata,0,len);
3908 pdata += 4 + len;
3909 data_size = PTR_DIFF(pdata,(*ppdata));
3910 *fixed_portion = 10;
3911 break;
3914 case SMB2_FILE_ALL_INFORMATION:
3916 unsigned int ea_size =
3917 estimate_ea_size(smb_fname->fsp);
3918 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
3919 put_long_date_full_timespec(conn->ts_res,pdata+0x00,&create_time_ts);
3920 put_long_date_full_timespec(conn->ts_res,pdata+0x08,&atime_ts);
3921 put_long_date_full_timespec(conn->ts_res,pdata+0x10,&mtime_ts); /* write time */
3922 put_long_date_full_timespec(conn->ts_res,pdata+0x18,&ctime_ts); /* change time */
3923 SIVAL(pdata, 0x20, mode);
3924 SIVAL(pdata, 0x24, 0); /* padding. */
3925 SBVAL(pdata, 0x28, allocation_size);
3926 SBVAL(pdata, 0x30, file_size);
3927 SIVAL(pdata, 0x38, nlink);
3928 SCVAL(pdata, 0x3C, delete_pending);
3929 SCVAL(pdata, 0x3D, (mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
3930 SSVAL(pdata, 0x3E, 0); /* padding */
3931 SBVAL(pdata, 0x40, file_id);
3932 SIVAL(pdata, 0x48, ea_size);
3933 SIVAL(pdata, 0x4C, access_mask);
3934 SBVAL(pdata, 0x50, pos);
3935 SIVAL(pdata, 0x58, mode); /*TODO: mode != mode fix this!!! */
3936 SIVAL(pdata, 0x5C, 0); /* No alignment needed. */
3938 pdata += 0x60;
3940 status = srvstr_push(dstart, flags2,
3941 pdata+4, dos_fname,
3942 PTR_DIFF(dend, pdata+4),
3943 STR_UNICODE, &len);
3944 if (!NT_STATUS_IS_OK(status)) {
3945 return status;
3947 SIVAL(pdata,0,len);
3948 pdata += 4 + len;
3949 data_size = PTR_DIFF(pdata,(*ppdata));
3950 *fixed_portion = 104;
3951 break;
3953 case SMB_FILE_INTERNAL_INFORMATION:
3955 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
3956 SBVAL(pdata, 0, file_id);
3957 data_size = 8;
3958 *fixed_portion = 8;
3959 break;
3961 case SMB_FILE_ACCESS_INFORMATION:
3962 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
3963 SIVAL(pdata, 0, access_mask);
3964 data_size = 4;
3965 *fixed_portion = 4;
3966 break;
3968 case SMB_FILE_NAME_INFORMATION:
3969 /* Pathname with leading '\'. */
3971 size_t byte_len;
3972 byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
3973 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
3974 SIVAL(pdata,0,byte_len);
3975 data_size = 4 + byte_len;
3976 break;
3979 case SMB_FILE_DISPOSITION_INFORMATION:
3980 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
3981 data_size = 1;
3982 SCVAL(pdata,0,delete_pending);
3983 *fixed_portion = 1;
3984 break;
3986 case SMB_FILE_POSITION_INFORMATION:
3987 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
3988 data_size = 8;
3989 SOFF_T(pdata,0,pos);
3990 *fixed_portion = 8;
3991 break;
3993 case SMB_FILE_MODE_INFORMATION:
3994 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
3995 SIVAL(pdata,0,mode);
3996 data_size = 4;
3997 *fixed_portion = 4;
3998 break;
4000 case SMB_FILE_ALIGNMENT_INFORMATION:
4001 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
4002 SIVAL(pdata,0,0); /* No alignment needed. */
4003 data_size = 4;
4004 *fixed_portion = 4;
4005 break;
4008 * NT4 server just returns "invalid query" to this - if we try
4009 * to answer it then NTws gets a BSOD! (tridge). W2K seems to
4010 * want this. JRA.
4012 /* The first statement above is false - verified using Thursby
4013 * client against NT4 -- gcolley.
4015 case SMB_QUERY_FILE_STREAM_INFO:
4016 case SMB_FILE_STREAM_INFORMATION: {
4017 unsigned int num_streams = 0;
4018 struct stream_struct *streams = NULL;
4020 DEBUG(10,("smbd_do_qfilepathinfo: "
4021 "SMB_FILE_STREAM_INFORMATION\n"));
4023 if (is_ntfs_stream_smb_fname(smb_fname)) {
4024 return NT_STATUS_INVALID_PARAMETER;
4027 status = vfs_fstreaminfo(fsp,
4028 mem_ctx,
4029 &num_streams,
4030 &streams);
4032 if (!NT_STATUS_IS_OK(status)) {
4033 DEBUG(10, ("could not get stream info: %s\n",
4034 nt_errstr(status)));
4035 return status;
4038 status = marshall_stream_info(num_streams, streams,
4039 pdata, max_data_bytes,
4040 &data_size);
4042 if (!NT_STATUS_IS_OK(status)) {
4043 DEBUG(10, ("marshall_stream_info failed: %s\n",
4044 nt_errstr(status)));
4045 TALLOC_FREE(streams);
4046 return status;
4049 TALLOC_FREE(streams);
4051 *fixed_portion = 32;
4053 break;
4055 case SMB_QUERY_COMPRESSION_INFO:
4056 case SMB_FILE_COMPRESSION_INFORMATION:
4057 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
4058 SOFF_T(pdata,0,file_size);
4059 SIVAL(pdata,8,0); /* ??? */
4060 SIVAL(pdata,12,0); /* ??? */
4061 data_size = 16;
4062 *fixed_portion = 16;
4063 break;
4065 case SMB_FILE_NETWORK_OPEN_INFORMATION:
4066 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
4067 put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
4068 put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
4069 put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
4070 put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
4071 SOFF_T(pdata,32,allocation_size);
4072 SOFF_T(pdata,40,file_size);
4073 SIVAL(pdata,48,mode);
4074 SIVAL(pdata,52,0); /* ??? */
4075 data_size = 56;
4076 *fixed_portion = 56;
4077 break;
4079 case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
4080 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
4081 SIVAL(pdata,0,mode);
4082 SIVAL(pdata,4,0);
4083 data_size = 8;
4084 *fixed_portion = 8;
4085 break;
4088 * CIFS UNIX Extensions.
4091 case SMB_QUERY_FILE_UNIX_BASIC:
4093 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
4094 data_size = PTR_DIFF(pdata,(*ppdata));
4096 DEBUG(4,("smbd_do_qfilepathinfo: "
4097 "SMB_QUERY_FILE_UNIX_BASIC\n"));
4098 dump_data(4, (uint8_t *)(*ppdata), data_size);
4100 break;
4102 case SMB_QUERY_FILE_UNIX_INFO2:
4104 pdata = store_file_unix_basic_info2(conn, pdata, fsp, psbuf);
4105 data_size = PTR_DIFF(pdata,(*ppdata));
4108 int i;
4109 DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));
4111 for (i=0; i<100; i++)
4112 DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
4113 DEBUG(4,("\n"));
4116 break;
4118 case SMB_QUERY_FILE_UNIX_LINK:
4120 status = smb_unix_read_symlink(conn,
4121 req,
4122 smb_fname,
4123 pdata,
4124 data_size,
4125 &data_size);
4126 if (!NT_STATUS_IS_OK(status)) {
4127 return status;
4129 break;
4132 #if defined(HAVE_POSIX_ACLS)
4133 case SMB_QUERY_POSIX_ACL:
4135 status = smb_query_posix_acl(conn,
4136 req,
4137 fsp,
4138 smb_fname,
4139 pdata,
4140 data_size,
4141 &data_size);
4142 if (!NT_STATUS_IS_OK(status)) {
4143 return status;
4145 break;
4147 #endif
4150 case SMB_QUERY_POSIX_LOCK:
4152 uint64_t count;
4153 uint64_t offset;
4154 uint64_t smblctx;
4155 enum brl_type lock_type;
4157 /* We need an open file with a real fd for this. */
4158 if (fsp == NULL ||
4159 fsp->fsp_flags.is_pathref ||
4160 fsp_get_io_fd(fsp) == -1)
4162 return NT_STATUS_INVALID_LEVEL;
4165 if (lock_data_count != POSIX_LOCK_DATA_SIZE) {
4166 return NT_STATUS_INVALID_PARAMETER;
4169 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
4170 case POSIX_LOCK_TYPE_READ:
4171 lock_type = READ_LOCK;
4172 break;
4173 case POSIX_LOCK_TYPE_WRITE:
4174 lock_type = WRITE_LOCK;
4175 break;
4176 case POSIX_LOCK_TYPE_UNLOCK:
4177 default:
4178 /* There's no point in asking for an unlock... */
4179 return NT_STATUS_INVALID_PARAMETER;
4182 smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
4183 offset = BVAL(pdata,POSIX_LOCK_START_OFFSET);
4184 count = BVAL(pdata,POSIX_LOCK_LEN_OFFSET);
4186 status = query_lock(fsp,
4187 &smblctx,
4188 &count,
4189 &offset,
4190 &lock_type,
4191 POSIX_LOCK);
4193 if (ERROR_WAS_LOCK_DENIED(status)) {
4194 /* Here we need to report who has it locked... */
4195 data_size = POSIX_LOCK_DATA_SIZE;
4197 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
4198 SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
4199 SIVAL(pdata, POSIX_LOCK_PID_OFFSET, (uint32_t)smblctx);
4200 SBVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
4201 SBVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
4203 } else if (NT_STATUS_IS_OK(status)) {
4204 /* For success we just return a copy of what we sent
4205 with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
4206 data_size = POSIX_LOCK_DATA_SIZE;
4207 memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
4208 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
4209 } else {
4210 return status;
4212 break;
4215 default:
4216 return NT_STATUS_INVALID_LEVEL;
4219 *pdata_size = data_size;
4220 return NT_STATUS_OK;
4223 /****************************************************************************
4224 Set a hard link (called by UNIX extensions and by NT rename with HARD link
4225 code.
4226 ****************************************************************************/
4228 NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
4229 connection_struct *conn,
4230 struct smb_request *req,
4231 bool overwrite_if_exists,
4232 const struct smb_filename *smb_fname_old,
4233 struct smb_filename *smb_fname_new)
4235 NTSTATUS status = NT_STATUS_OK;
4236 int ret;
4237 bool ok;
4238 struct smb_filename *parent_fname_old = NULL;
4239 struct smb_filename *base_name_old = NULL;
4240 struct smb_filename *parent_fname_new = NULL;
4241 struct smb_filename *base_name_new = NULL;
4243 /* source must already exist. */
4244 if (!VALID_STAT(smb_fname_old->st)) {
4245 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
4246 goto out;
4249 /* No links from a directory. */
4250 if (S_ISDIR(smb_fname_old->st.st_ex_mode)) {
4251 status = NT_STATUS_FILE_IS_A_DIRECTORY;
4252 goto out;
4255 /* Setting a hardlink to/from a stream isn't currently supported. */
4256 ok = is_ntfs_stream_smb_fname(smb_fname_old);
4257 if (ok) {
4258 DBG_DEBUG("Old name has streams\n");
4259 status = NT_STATUS_INVALID_PARAMETER;
4260 goto out;
4262 ok = is_ntfs_stream_smb_fname(smb_fname_new);
4263 if (ok) {
4264 DBG_DEBUG("New name has streams\n");
4265 status = NT_STATUS_INVALID_PARAMETER;
4266 goto out;
4269 status = parent_pathref(talloc_tos(),
4270 conn->cwd_fsp,
4271 smb_fname_old,
4272 &parent_fname_old,
4273 &base_name_old);
4274 if (!NT_STATUS_IS_OK(status)) {
4275 goto out;
4278 status = parent_pathref(talloc_tos(),
4279 conn->cwd_fsp,
4280 smb_fname_new,
4281 &parent_fname_new,
4282 &base_name_new);
4283 if (!NT_STATUS_IS_OK(status)) {
4284 goto out;
4287 if (VALID_STAT(smb_fname_new->st)) {
4288 if (overwrite_if_exists) {
4289 if (S_ISDIR(smb_fname_new->st.st_ex_mode)) {
4290 status = NT_STATUS_FILE_IS_A_DIRECTORY;
4291 goto out;
4293 status = unlink_internals(conn,
4294 req,
4295 FILE_ATTRIBUTE_NORMAL,
4296 smb_fname_new);
4297 if (!NT_STATUS_IS_OK(status)) {
4298 goto out;
4300 } else {
4301 /* Disallow if newname already exists. */
4302 status = NT_STATUS_OBJECT_NAME_COLLISION;
4303 goto out;
4307 DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n",
4308 smb_fname_old->base_name, smb_fname_new->base_name));
4310 ret = SMB_VFS_LINKAT(conn,
4311 parent_fname_old->fsp,
4312 base_name_old,
4313 parent_fname_new->fsp,
4314 base_name_new,
4317 if (ret != 0) {
4318 status = map_nt_error_from_unix(errno);
4319 DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
4320 nt_errstr(status), smb_fname_old->base_name,
4321 smb_fname_new->base_name));
4324 out:
4326 TALLOC_FREE(parent_fname_old);
4327 TALLOC_FREE(parent_fname_new);
4328 return status;
4331 /****************************************************************************
4332 Deal with setting the time from any of the setfilepathinfo functions.
4333 NOTE !!!! The check for FILE_WRITE_ATTRIBUTES access must be done *before*
4334 calling this function.
4335 ****************************************************************************/
4337 NTSTATUS smb_set_file_time(connection_struct *conn,
4338 files_struct *fsp,
4339 struct smb_filename *smb_fname,
4340 struct smb_file_time *ft,
4341 bool setting_write_time)
4343 struct files_struct *set_fsp = NULL;
4344 struct timeval_buf tbuf[4];
4345 uint32_t action =
4346 FILE_NOTIFY_CHANGE_LAST_ACCESS
4347 |FILE_NOTIFY_CHANGE_LAST_WRITE
4348 |FILE_NOTIFY_CHANGE_CREATION;
4349 int ret;
4351 if (!VALID_STAT(smb_fname->st)) {
4352 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4355 if (fsp == NULL) {
4356 /* A symlink */
4357 return NT_STATUS_OK;
4360 set_fsp = metadata_fsp(fsp);
4362 /* get some defaults (no modifications) if any info is zero or -1. */
4363 if (is_omit_timespec(&ft->create_time)) {
4364 action &= ~FILE_NOTIFY_CHANGE_CREATION;
4367 if (is_omit_timespec(&ft->atime)) {
4368 action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
4371 if (is_omit_timespec(&ft->mtime)) {
4372 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
4375 if (!setting_write_time) {
4376 /* ft->mtime comes from change time, not write time. */
4377 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
4380 /* Ensure the resolution is the correct for
4381 * what we can store on this filesystem. */
4383 round_timespec(conn->ts_res, &ft->create_time);
4384 round_timespec(conn->ts_res, &ft->ctime);
4385 round_timespec(conn->ts_res, &ft->atime);
4386 round_timespec(conn->ts_res, &ft->mtime);
4388 DBG_DEBUG("smb_set_filetime: actime: %s\n ",
4389 timespec_string_buf(&ft->atime, true, &tbuf[0]));
4390 DBG_DEBUG("smb_set_filetime: modtime: %s\n ",
4391 timespec_string_buf(&ft->mtime, true, &tbuf[1]));
4392 DBG_DEBUG("smb_set_filetime: ctime: %s\n ",
4393 timespec_string_buf(&ft->ctime, true, &tbuf[2]));
4394 DBG_DEBUG("smb_set_file_time: createtime: %s\n ",
4395 timespec_string_buf(&ft->create_time, true, &tbuf[3]));
4397 if (setting_write_time) {
4399 * This was a Windows setfileinfo on an open file.
4400 * NT does this a lot. We also need to
4401 * set the time here, as it can be read by
4402 * FindFirst/FindNext and with the patch for bug #2045
4403 * in smbd/fileio.c it ensures that this timestamp is
4404 * kept sticky even after a write. We save the request
4405 * away and will set it on file close and after a write. JRA.
4408 DBG_DEBUG("setting pending modtime to %s\n",
4409 timespec_string_buf(&ft->mtime, true, &tbuf[0]));
4411 if (set_fsp != NULL) {
4412 set_sticky_write_time_fsp(set_fsp, ft->mtime);
4413 } else {
4414 set_sticky_write_time_path(
4415 vfs_file_id_from_sbuf(conn, &smb_fname->st),
4416 ft->mtime);
4420 DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
4422 ret = file_ntimes(conn, set_fsp, ft);
4423 if (ret != 0) {
4424 return map_nt_error_from_unix(errno);
4427 notify_fname(conn, NOTIFY_ACTION_MODIFIED, action,
4428 smb_fname->base_name);
4429 return NT_STATUS_OK;
4432 /****************************************************************************
4433 Deal with setting the dosmode from any of the setfilepathinfo functions.
4434 NB. The check for FILE_WRITE_ATTRIBUTES access on this path must have been
4435 done before calling this function.
4436 ****************************************************************************/
4438 static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
4439 struct files_struct *fsp,
4440 uint32_t dosmode)
4442 struct files_struct *dos_fsp = NULL;
4443 uint32_t current_dosmode;
4444 int ret;
4446 if (!VALID_STAT(fsp->fsp_name->st)) {
4447 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4450 dos_fsp = metadata_fsp(fsp);
4452 if (dosmode != 0) {
4453 if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
4454 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
4455 } else {
4456 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
4460 DBG_DEBUG("dosmode: 0x%" PRIx32 "\n", dosmode);
4462 /* check the mode isn't different, before changing it */
4463 if (dosmode == 0) {
4464 return NT_STATUS_OK;
4466 current_dosmode = fdos_mode(dos_fsp);
4467 if (dosmode == current_dosmode) {
4468 return NT_STATUS_OK;
4471 DBG_DEBUG("file %s : setting dos mode 0x%" PRIx32 "\n",
4472 fsp_str_dbg(dos_fsp), dosmode);
4474 ret = file_set_dosmode(conn, dos_fsp->fsp_name, dosmode, NULL, false);
4475 if (ret != 0) {
4476 DBG_WARNING("file_set_dosmode of %s failed: %s\n",
4477 fsp_str_dbg(dos_fsp), strerror(errno));
4478 return map_nt_error_from_unix(errno);
4481 return NT_STATUS_OK;
4484 /****************************************************************************
4485 Deal with setting the size from any of the setfilepathinfo functions.
4486 ****************************************************************************/
4488 static NTSTATUS smb_set_file_size(connection_struct *conn,
4489 struct smb_request *req,
4490 files_struct *fsp,
4491 struct smb_filename *smb_fname,
4492 const SMB_STRUCT_STAT *psbuf,
4493 off_t size,
4494 bool fail_after_createfile)
4496 NTSTATUS status = NT_STATUS_OK;
4497 files_struct *new_fsp = NULL;
4499 if (!VALID_STAT(*psbuf)) {
4500 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4503 DBG_INFO("size: %"PRIu64", file_size_stat=%"PRIu64"\n",
4504 (uint64_t)size,
4505 get_file_size_stat(psbuf));
4507 if (size == get_file_size_stat(psbuf)) {
4508 if (fsp == NULL) {
4509 return NT_STATUS_OK;
4511 if (!fsp->fsp_flags.modified) {
4512 return NT_STATUS_OK;
4514 trigger_write_time_update_immediate(fsp);
4515 return NT_STATUS_OK;
4518 DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n",
4519 smb_fname_str_dbg(smb_fname), (double)size));
4521 if (fsp &&
4522 !fsp->fsp_flags.is_pathref &&
4523 fsp_get_io_fd(fsp) != -1)
4525 /* Handle based call. */
4526 if (!(fsp->access_mask & FILE_WRITE_DATA)) {
4527 return NT_STATUS_ACCESS_DENIED;
4530 if (vfs_set_filelen(fsp, size) == -1) {
4531 return map_nt_error_from_unix(errno);
4533 trigger_write_time_update_immediate(fsp);
4534 return NT_STATUS_OK;
4537 status = SMB_VFS_CREATE_FILE(
4538 conn, /* conn */
4539 req, /* req */
4540 smb_fname, /* fname */
4541 FILE_WRITE_DATA, /* access_mask */
4542 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
4543 FILE_SHARE_DELETE),
4544 FILE_OPEN, /* create_disposition*/
4545 0, /* create_options */
4546 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
4547 0, /* oplock_request */
4548 NULL, /* lease */
4549 0, /* allocation_size */
4550 0, /* private_flags */
4551 NULL, /* sd */
4552 NULL, /* ea_list */
4553 &new_fsp, /* result */
4554 NULL, /* pinfo */
4555 NULL, NULL); /* create context */
4557 if (!NT_STATUS_IS_OK(status)) {
4558 /* NB. We check for open_was_deferred in the caller. */
4559 return status;
4562 /* See RAW-SFILEINFO-END-OF-FILE */
4563 if (fail_after_createfile) {
4564 close_file_free(req, &new_fsp, NORMAL_CLOSE);
4565 return NT_STATUS_INVALID_LEVEL;
4568 if (vfs_set_filelen(new_fsp, size) == -1) {
4569 status = map_nt_error_from_unix(errno);
4570 close_file_free(req, &new_fsp, NORMAL_CLOSE);
4571 return status;
4574 trigger_write_time_update_immediate(new_fsp);
4575 close_file_free(req, &new_fsp, NORMAL_CLOSE);
4576 return NT_STATUS_OK;
4579 /****************************************************************************
4580 Deal with SMB_INFO_SET_EA.
4581 ****************************************************************************/
4583 static NTSTATUS smb_info_set_ea(connection_struct *conn,
4584 const char *pdata,
4585 int total_data,
4586 files_struct *fsp,
4587 struct smb_filename *smb_fname)
4589 struct ea_list *ea_list = NULL;
4590 TALLOC_CTX *ctx = NULL;
4591 NTSTATUS status = NT_STATUS_OK;
4593 if (total_data < 10) {
4595 /* OS/2 workplace shell seems to send SET_EA requests of "null"
4596 length. They seem to have no effect. Bug #3212. JRA */
4598 if ((total_data == 4) && (IVAL(pdata,0) == 4)) {
4599 /* We're done. We only get EA info in this call. */
4600 return NT_STATUS_OK;
4603 return NT_STATUS_INVALID_PARAMETER;
4606 if (IVAL(pdata,0) > total_data) {
4607 DEBUG(10,("smb_info_set_ea: bad total data size (%u) > %u\n",
4608 IVAL(pdata,0), (unsigned int)total_data));
4609 return NT_STATUS_INVALID_PARAMETER;
4612 ctx = talloc_tos();
4613 ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
4614 if (!ea_list) {
4615 return NT_STATUS_INVALID_PARAMETER;
4618 if (fsp == NULL) {
4620 * The only way fsp can be NULL here is if
4621 * smb_fname points at a symlink and
4622 * and we're in POSIX context.
4623 * Ensure this is the case.
4625 * In this case we cannot set the EA.
4627 SMB_ASSERT(smb_fname->flags & SMB_FILENAME_POSIX_PATH);
4628 return NT_STATUS_ACCESS_DENIED;
4631 status = set_ea(conn, fsp, ea_list);
4633 return status;
4636 /****************************************************************************
4637 Deal with SMB_FILE_FULL_EA_INFORMATION set.
4638 ****************************************************************************/
4640 static NTSTATUS smb_set_file_full_ea_info(connection_struct *conn,
4641 const char *pdata,
4642 int total_data,
4643 files_struct *fsp)
4645 struct ea_list *ea_list = NULL;
4646 NTSTATUS status;
4648 if (fsp == NULL) {
4649 return NT_STATUS_INVALID_HANDLE;
4652 if (!lp_ea_support(SNUM(conn))) {
4653 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u but "
4654 "EA's not supported.\n",
4655 (unsigned int)total_data));
4656 return NT_STATUS_EAS_NOT_SUPPORTED;
4659 if (total_data < 10) {
4660 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u "
4661 "too small.\n",
4662 (unsigned int)total_data));
4663 return NT_STATUS_INVALID_PARAMETER;
4666 ea_list = read_nttrans_ea_list(talloc_tos(),
4667 pdata,
4668 total_data);
4670 if (!ea_list) {
4671 return NT_STATUS_INVALID_PARAMETER;
4674 status = set_ea(conn, fsp, ea_list);
4676 DEBUG(10, ("smb_set_file_full_ea_info on file %s returned %s\n",
4677 smb_fname_str_dbg(fsp->fsp_name),
4678 nt_errstr(status) ));
4680 return status;
4684 /****************************************************************************
4685 Deal with SMB_SET_FILE_DISPOSITION_INFO.
4686 ****************************************************************************/
4688 static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
4689 const char *pdata,
4690 int total_data,
4691 files_struct *fsp,
4692 struct smb_filename *smb_fname)
4694 NTSTATUS status = NT_STATUS_OK;
4695 bool delete_on_close;
4696 uint32_t dosmode = 0;
4698 if (total_data < 1) {
4699 return NT_STATUS_INVALID_PARAMETER;
4702 if (fsp == NULL) {
4703 return NT_STATUS_INVALID_HANDLE;
4706 delete_on_close = (CVAL(pdata,0) ? True : False);
4707 dosmode = fdos_mode(fsp);
4709 DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
4710 "delete_on_close = %u\n",
4711 smb_fname_str_dbg(smb_fname),
4712 (unsigned int)dosmode,
4713 (unsigned int)delete_on_close ));
4715 if (delete_on_close) {
4716 status = can_set_delete_on_close(fsp, dosmode);
4717 if (!NT_STATUS_IS_OK(status)) {
4718 return status;
4722 /* The set is across all open files on this dev/inode pair. */
4723 if (!set_delete_on_close(fsp, delete_on_close,
4724 conn->session_info->security_token,
4725 conn->session_info->unix_token)) {
4726 return NT_STATUS_ACCESS_DENIED;
4728 return NT_STATUS_OK;
4731 /****************************************************************************
4732 Deal with SMB_FILE_POSITION_INFORMATION.
4733 ****************************************************************************/
4735 static NTSTATUS smb_file_position_information(connection_struct *conn,
4736 const char *pdata,
4737 int total_data,
4738 files_struct *fsp)
4740 uint64_t position_information;
4742 if (total_data < 8) {
4743 return NT_STATUS_INVALID_PARAMETER;
4746 if (fsp == NULL) {
4747 /* Ignore on pathname based set. */
4748 return NT_STATUS_OK;
4751 position_information = (uint64_t)IVAL(pdata,0);
4752 position_information |= (((uint64_t)IVAL(pdata,4)) << 32);
4754 DEBUG(10,("smb_file_position_information: Set file position "
4755 "information for file %s to %.0f\n", fsp_str_dbg(fsp),
4756 (double)position_information));
4757 fh_set_position_information(fsp->fh, position_information);
4758 return NT_STATUS_OK;
4761 /****************************************************************************
4762 Deal with SMB_FILE_MODE_INFORMATION.
4763 ****************************************************************************/
4765 static NTSTATUS smb_file_mode_information(connection_struct *conn,
4766 const char *pdata,
4767 int total_data)
4769 uint32_t mode;
4771 if (total_data < 4) {
4772 return NT_STATUS_INVALID_PARAMETER;
4774 mode = IVAL(pdata,0);
4775 if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
4776 return NT_STATUS_INVALID_PARAMETER;
4778 return NT_STATUS_OK;
4781 /****************************************************************************
4782 Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
4783 ****************************************************************************/
4785 static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
4786 struct smb_request *req,
4787 const char *pdata,
4788 int total_data,
4789 struct smb_filename *new_smb_fname)
4791 char *link_target = NULL;
4792 struct smb_filename target_fname;
4793 TALLOC_CTX *ctx = talloc_tos();
4794 NTSTATUS status;
4795 int ret;
4796 struct smb_filename *parent_fname = NULL;
4797 struct smb_filename *base_name = NULL;
4799 /* Set a symbolic link. */
4800 /* Don't allow this if follow links is false. */
4802 if (total_data == 0) {
4803 return NT_STATUS_INVALID_PARAMETER;
4806 if (!lp_follow_symlinks(SNUM(conn))) {
4807 return NT_STATUS_ACCESS_DENIED;
4810 srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
4811 total_data, STR_TERMINATE);
4813 if (!link_target) {
4814 return NT_STATUS_INVALID_PARAMETER;
4817 target_fname = (struct smb_filename) {
4818 .base_name = link_target,
4821 /* Removes @GMT tokens if any */
4822 status = canonicalize_snapshot_path(&target_fname, UCF_GMT_PATHNAME, 0);
4823 if (!NT_STATUS_IS_OK(status)) {
4824 return status;
4827 DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
4828 new_smb_fname->base_name, link_target ));
4830 status = parent_pathref(talloc_tos(),
4831 conn->cwd_fsp,
4832 new_smb_fname,
4833 &parent_fname,
4834 &base_name);
4835 if (!NT_STATUS_IS_OK(status)) {
4836 return status;
4839 ret = SMB_VFS_SYMLINKAT(conn,
4840 &target_fname,
4841 parent_fname->fsp,
4842 base_name);
4843 if (ret != 0) {
4844 TALLOC_FREE(parent_fname);
4845 return map_nt_error_from_unix(errno);
4848 TALLOC_FREE(parent_fname);
4849 return NT_STATUS_OK;
4852 /****************************************************************************
4853 Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
4854 ****************************************************************************/
4856 static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
4857 struct smb_request *req,
4858 const char *pdata, int total_data,
4859 struct smb_filename *smb_fname_new)
4861 char *oldname = NULL;
4862 struct smb_filename *smb_fname_old = NULL;
4863 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4864 TALLOC_CTX *ctx = talloc_tos();
4865 NTSTATUS status = NT_STATUS_OK;
4867 /* Set a hard link. */
4868 if (total_data == 0) {
4869 return NT_STATUS_INVALID_PARAMETER;
4872 if (req->posix_pathnames) {
4873 srvstr_get_path_posix(ctx,
4874 pdata,
4875 req->flags2,
4876 &oldname,
4877 pdata,
4878 total_data,
4879 STR_TERMINATE,
4880 &status);
4881 } else {
4882 srvstr_get_path(ctx,
4883 pdata,
4884 req->flags2,
4885 &oldname,
4886 pdata,
4887 total_data,
4888 STR_TERMINATE,
4889 &status);
4891 if (!NT_STATUS_IS_OK(status)) {
4892 return status;
4895 DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
4896 smb_fname_str_dbg(smb_fname_new), oldname));
4898 status = filename_convert(ctx,
4899 conn,
4900 oldname,
4901 ucf_flags,
4903 &smb_fname_old);
4904 if (!NT_STATUS_IS_OK(status)) {
4905 return status;
4908 return hardlink_internals(ctx, conn, req, false,
4909 smb_fname_old, smb_fname_new);
4912 /****************************************************************************
4913 Deal with SMB2_FILE_RENAME_INFORMATION_INTERNAL
4914 ****************************************************************************/
4916 static NTSTATUS smb2_file_rename_information(connection_struct *conn,
4917 struct smb_request *req,
4918 const char *pdata,
4919 int total_data,
4920 files_struct *fsp,
4921 struct smb_filename *smb_fname_src)
4923 bool overwrite;
4924 uint32_t len;
4925 char *newname = NULL;
4926 struct smb_filename *smb_fname_dst = NULL;
4927 const char *dst_original_lcomp = NULL;
4928 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4929 NTSTATUS status = NT_STATUS_OK;
4930 TALLOC_CTX *ctx = talloc_tos();
4932 if (!fsp) {
4933 return NT_STATUS_INVALID_HANDLE;
4936 if (total_data < 20) {
4937 return NT_STATUS_INVALID_PARAMETER;
4940 overwrite = (CVAL(pdata,0) ? True : False);
4941 len = IVAL(pdata,16);
4943 if (len > (total_data - 20) || (len == 0)) {
4944 return NT_STATUS_INVALID_PARAMETER;
4947 if (req->posix_pathnames) {
4948 srvstr_get_path_posix(ctx,
4949 pdata,
4950 req->flags2,
4951 &newname,
4952 &pdata[20],
4953 len,
4954 STR_TERMINATE,
4955 &status);
4956 } else {
4957 srvstr_get_path(ctx,
4958 pdata,
4959 req->flags2,
4960 &newname,
4961 &pdata[20],
4962 len,
4963 STR_TERMINATE,
4964 &status);
4966 if (!NT_STATUS_IS_OK(status)) {
4967 return status;
4970 DEBUG(10,("smb2_file_rename_information: got name |%s|\n",
4971 newname));
4973 status = filename_convert(ctx,
4974 conn,
4975 newname,
4976 ucf_flags,
4978 &smb_fname_dst);
4979 if (!NT_STATUS_IS_OK(status)) {
4980 return status;
4983 if (fsp->base_fsp) {
4984 /* newname must be a stream name. */
4985 if (newname[0] != ':') {
4986 return NT_STATUS_NOT_SUPPORTED;
4989 /* Create an smb_fname to call rename_internals_fsp() with. */
4990 smb_fname_dst = synthetic_smb_fname(talloc_tos(),
4991 fsp->base_fsp->fsp_name->base_name,
4992 newname,
4993 NULL,
4994 fsp->base_fsp->fsp_name->twrp,
4995 fsp->base_fsp->fsp_name->flags);
4996 if (smb_fname_dst == NULL) {
4997 status = NT_STATUS_NO_MEMORY;
4998 goto out;
5003 * Set the original last component, since
5004 * rename_internals_fsp() requires it.
5006 dst_original_lcomp = get_original_lcomp(smb_fname_dst,
5007 conn,
5008 newname,
5009 ucf_flags);
5010 if (dst_original_lcomp == NULL) {
5011 status = NT_STATUS_NO_MEMORY;
5012 goto out;
5015 DEBUG(10,("smb2_file_rename_information: "
5016 "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
5017 fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
5018 smb_fname_str_dbg(smb_fname_dst)));
5019 status = rename_internals_fsp(conn,
5020 fsp,
5021 smb_fname_dst,
5022 dst_original_lcomp,
5023 (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM),
5024 overwrite);
5026 out:
5027 TALLOC_FREE(smb_fname_dst);
5028 return status;
5031 static NTSTATUS smb_file_link_information(connection_struct *conn,
5032 struct smb_request *req,
5033 const char *pdata,
5034 int total_data,
5035 files_struct *fsp,
5036 struct smb_filename *smb_fname_src)
5038 bool overwrite;
5039 uint32_t len;
5040 char *newname = NULL;
5041 struct smb_filename *smb_fname_dst = NULL;
5042 NTSTATUS status = NT_STATUS_OK;
5043 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
5044 TALLOC_CTX *ctx = talloc_tos();
5046 if (!fsp) {
5047 return NT_STATUS_INVALID_HANDLE;
5050 if (total_data < 20) {
5051 return NT_STATUS_INVALID_PARAMETER;
5054 overwrite = (CVAL(pdata,0) ? true : false);
5055 len = IVAL(pdata,16);
5057 if (len > (total_data - 20) || (len == 0)) {
5058 return NT_STATUS_INVALID_PARAMETER;
5061 if (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH) {
5062 srvstr_get_path_posix(ctx,
5063 pdata,
5064 req->flags2,
5065 &newname,
5066 &pdata[20],
5067 len,
5068 STR_TERMINATE,
5069 &status);
5070 ucf_flags |= UCF_POSIX_PATHNAMES;
5071 } else {
5072 srvstr_get_path(ctx,
5073 pdata,
5074 req->flags2,
5075 &newname,
5076 &pdata[20],
5077 len,
5078 STR_TERMINATE,
5079 &status);
5081 if (!NT_STATUS_IS_OK(status)) {
5082 return status;
5085 DEBUG(10,("smb_file_link_information: got name |%s|\n",
5086 newname));
5088 status = filename_convert(ctx,
5089 conn,
5090 newname,
5091 ucf_flags,
5093 &smb_fname_dst);
5094 if (!NT_STATUS_IS_OK(status)) {
5095 return status;
5098 if (fsp->base_fsp) {
5099 /* No stream names. */
5100 return NT_STATUS_NOT_SUPPORTED;
5103 DEBUG(10,("smb_file_link_information: "
5104 "SMB_FILE_LINK_INFORMATION (%s) %s -> %s\n",
5105 fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
5106 smb_fname_str_dbg(smb_fname_dst)));
5107 status = hardlink_internals(ctx,
5108 conn,
5109 req,
5110 overwrite,
5111 fsp->fsp_name,
5112 smb_fname_dst);
5114 TALLOC_FREE(smb_fname_dst);
5115 return status;
5118 /****************************************************************************
5119 Deal with SMB_FILE_RENAME_INFORMATION.
5120 ****************************************************************************/
5122 static NTSTATUS smb_file_rename_information(connection_struct *conn,
5123 struct smb_request *req,
5124 const char *pdata,
5125 int total_data,
5126 files_struct *fsp,
5127 struct smb_filename *smb_fname_src)
5129 bool overwrite;
5130 uint32_t root_fid;
5131 uint32_t len;
5132 char *newname = NULL;
5133 struct smb_filename *smb_fname_dst = NULL;
5134 const char *dst_original_lcomp = NULL;
5135 NTSTATUS status = NT_STATUS_OK;
5136 char *p;
5137 TALLOC_CTX *ctx = talloc_tos();
5139 if (total_data < 13) {
5140 return NT_STATUS_INVALID_PARAMETER;
5143 overwrite = (CVAL(pdata,0) ? True : False);
5144 root_fid = IVAL(pdata,4);
5145 len = IVAL(pdata,8);
5147 if (len > (total_data - 12) || (len == 0) || (root_fid != 0)) {
5148 return NT_STATUS_INVALID_PARAMETER;
5151 if (req->posix_pathnames) {
5152 srvstr_get_path_posix(ctx,
5153 pdata,
5154 req->flags2,
5155 &newname,
5156 &pdata[12],
5157 len,
5159 &status);
5160 } else {
5161 srvstr_get_path(ctx,
5162 pdata,
5163 req->flags2,
5164 &newname,
5165 &pdata[12],
5166 len,
5168 &status);
5170 if (!NT_STATUS_IS_OK(status)) {
5171 return status;
5174 DEBUG(10,("smb_file_rename_information: got name |%s|\n",
5175 newname));
5177 /* Check the new name has no '/' characters. */
5178 if (strchr_m(newname, '/')) {
5179 return NT_STATUS_NOT_SUPPORTED;
5182 if (fsp && fsp->base_fsp) {
5183 /* newname must be a stream name. */
5184 if (newname[0] != ':') {
5185 return NT_STATUS_NOT_SUPPORTED;
5188 /* Create an smb_fname to call rename_internals_fsp() with. */
5189 smb_fname_dst = synthetic_smb_fname(talloc_tos(),
5190 fsp->base_fsp->fsp_name->base_name,
5191 newname,
5192 NULL,
5193 fsp->base_fsp->fsp_name->twrp,
5194 fsp->base_fsp->fsp_name->flags);
5195 if (smb_fname_dst == NULL) {
5196 status = NT_STATUS_NO_MEMORY;
5197 goto out;
5201 * Get the original last component, since
5202 * rename_internals_fsp() requires it.
5204 dst_original_lcomp = get_original_lcomp(smb_fname_dst,
5205 conn,
5206 newname,
5208 if (dst_original_lcomp == NULL) {
5209 status = NT_STATUS_NO_MEMORY;
5210 goto out;
5213 } else {
5215 * Build up an smb_fname_dst based on the filename passed in.
5216 * We basically just strip off the last component, and put on
5217 * the newname instead.
5219 char *base_name = NULL;
5220 uint32_t ucf_flags = ucf_flags_from_smb_request(req);
5222 /* newname must *not* be a stream name. */
5223 if (newname[0] == ':') {
5224 return NT_STATUS_NOT_SUPPORTED;
5228 * Strip off the last component (filename) of the path passed
5229 * in.
5231 base_name = talloc_strdup(ctx, smb_fname_src->base_name);
5232 if (!base_name) {
5233 return NT_STATUS_NO_MEMORY;
5235 p = strrchr_m(base_name, '/');
5236 if (p) {
5237 p[1] = '\0';
5238 } else {
5239 base_name = talloc_strdup(ctx, "");
5240 if (!base_name) {
5241 return NT_STATUS_NO_MEMORY;
5244 /* Append the new name. */
5245 base_name = talloc_asprintf_append(base_name,
5246 "%s",
5247 newname);
5248 if (!base_name) {
5249 return NT_STATUS_NO_MEMORY;
5252 status = filename_convert(ctx,
5253 conn,
5254 base_name,
5255 ucf_flags,
5257 &smb_fname_dst);
5259 if (!NT_STATUS_IS_OK(status)) {
5260 goto out;
5262 dst_original_lcomp = get_original_lcomp(smb_fname_dst,
5263 conn,
5264 newname,
5265 ucf_flags);
5266 if (dst_original_lcomp == NULL) {
5267 status = NT_STATUS_NO_MEMORY;
5268 goto out;
5272 if (fsp != NULL && fsp->fsp_flags.is_fsa) {
5273 DEBUG(10,("smb_file_rename_information: "
5274 "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
5275 fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
5276 smb_fname_str_dbg(smb_fname_dst)));
5277 status = rename_internals_fsp(conn,
5278 fsp,
5279 smb_fname_dst,
5280 dst_original_lcomp,
5282 overwrite);
5283 } else {
5284 DEBUG(10,("smb_file_rename_information: "
5285 "SMB_FILE_RENAME_INFORMATION %s -> %s\n",
5286 smb_fname_str_dbg(smb_fname_src),
5287 smb_fname_str_dbg(smb_fname_dst)));
5288 status = rename_internals(ctx,
5289 conn,
5290 req,
5291 smb_fname_src,
5292 smb_fname_dst,
5293 dst_original_lcomp,
5295 overwrite,
5296 FILE_WRITE_ATTRIBUTES);
5298 out:
5299 TALLOC_FREE(smb_fname_dst);
5300 return status;
5303 /****************************************************************************
5304 Deal with SMB_SET_POSIX_ACL.
5305 ****************************************************************************/
5307 #if defined(HAVE_POSIX_ACLS)
5308 static NTSTATUS smb_set_posix_acl(connection_struct *conn,
5309 struct smb_request *req,
5310 const char *pdata,
5311 int total_data_in,
5312 files_struct *fsp,
5313 struct smb_filename *smb_fname)
5315 uint16_t posix_acl_version;
5316 uint16_t num_file_acls;
5317 uint16_t num_def_acls;
5318 bool valid_file_acls = true;
5319 bool valid_def_acls = true;
5320 NTSTATUS status;
5321 unsigned int size_needed;
5322 unsigned int total_data;
5323 bool close_fsp = false;
5325 if (total_data_in < 0) {
5326 status = NT_STATUS_INVALID_PARAMETER;
5327 goto out;
5330 total_data = total_data_in;
5332 if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
5333 status = NT_STATUS_INVALID_PARAMETER;
5334 goto out;
5336 posix_acl_version = SVAL(pdata,0);
5337 num_file_acls = SVAL(pdata,2);
5338 num_def_acls = SVAL(pdata,4);
5340 if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
5341 valid_file_acls = false;
5342 num_file_acls = 0;
5345 if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
5346 valid_def_acls = false;
5347 num_def_acls = 0;
5350 if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
5351 status = NT_STATUS_INVALID_PARAMETER;
5352 goto out;
5355 /* Wrap checks. */
5356 if (num_file_acls + num_def_acls < num_file_acls) {
5357 status = NT_STATUS_INVALID_PARAMETER;
5358 goto out;
5361 size_needed = num_file_acls + num_def_acls;
5364 * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
5365 * than UINT_MAX, so check by division.
5367 if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
5368 status = NT_STATUS_INVALID_PARAMETER;
5369 goto out;
5372 size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
5373 if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
5374 status = NT_STATUS_INVALID_PARAMETER;
5375 goto out;
5377 size_needed += SMB_POSIX_ACL_HEADER_SIZE;
5379 if (total_data < size_needed) {
5380 status = NT_STATUS_INVALID_PARAMETER;
5381 goto out;
5385 * Ensure we always operate on a file descriptor, not just
5386 * the filename.
5388 if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
5389 uint32_t access_mask = SEC_STD_WRITE_OWNER|
5390 SEC_STD_WRITE_DAC|
5391 SEC_STD_READ_CONTROL|
5392 FILE_READ_ATTRIBUTES|
5393 FILE_WRITE_ATTRIBUTES;
5395 status = get_posix_fsp(conn,
5396 req,
5397 smb_fname,
5398 access_mask,
5399 &fsp);
5401 if (!NT_STATUS_IS_OK(status)) {
5402 goto out;
5404 close_fsp = true;
5407 /* Here we know fsp != NULL */
5408 SMB_ASSERT(fsp != NULL);
5410 status = refuse_symlink_fsp(fsp);
5411 if (!NT_STATUS_IS_OK(status)) {
5412 goto out;
5415 /* If we have a default acl, this *must* be a directory. */
5416 if (valid_def_acls && !fsp->fsp_flags.is_directory) {
5417 DBG_INFO("Can't set default acls on "
5418 "non-directory %s\n",
5419 fsp_str_dbg(fsp));
5420 return NT_STATUS_INVALID_HANDLE;
5423 DBG_DEBUG("file %s num_file_acls = %"PRIu16", "
5424 "num_def_acls = %"PRIu16"\n",
5425 fsp_str_dbg(fsp),
5426 num_file_acls,
5427 num_def_acls);
5429 /* Move pdata to the start of the file ACL entries. */
5430 pdata += SMB_POSIX_ACL_HEADER_SIZE;
5432 if (valid_file_acls) {
5433 status = set_unix_posix_acl(conn,
5434 fsp,
5435 num_file_acls,
5436 pdata);
5437 if (!NT_STATUS_IS_OK(status)) {
5438 goto out;
5442 /* Move pdata to the start of the default ACL entries. */
5443 pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
5445 if (valid_def_acls) {
5446 status = set_unix_posix_default_acl(conn,
5447 fsp,
5448 num_def_acls,
5449 pdata);
5450 if (!NT_STATUS_IS_OK(status)) {
5451 goto out;
5455 status = NT_STATUS_OK;
5457 out:
5459 if (close_fsp) {
5460 (void)close_file_free(req, &fsp, NORMAL_CLOSE);
5462 return status;
5464 #endif
5466 /****************************************************************************
5467 Deal with SMB_SET_FILE_BASIC_INFO.
5468 ****************************************************************************/
5470 static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
5471 const char *pdata,
5472 int total_data,
5473 files_struct *fsp,
5474 struct smb_filename *smb_fname)
5476 /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
5477 struct smb_file_time ft;
5478 uint32_t dosmode = 0;
5479 NTSTATUS status = NT_STATUS_OK;
5481 init_smb_file_time(&ft);
5483 if (total_data < 36) {
5484 return NT_STATUS_INVALID_PARAMETER;
5487 if (fsp == NULL) {
5488 return NT_STATUS_INVALID_HANDLE;
5491 status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES);
5492 if (!NT_STATUS_IS_OK(status)) {
5493 return status;
5496 /* Set the attributes */
5497 dosmode = IVAL(pdata,32);
5498 status = smb_set_file_dosmode(conn, fsp, dosmode);
5499 if (!NT_STATUS_IS_OK(status)) {
5500 return status;
5503 /* create time */
5504 ft.create_time = pull_long_date_full_timespec(pdata);
5506 /* access time */
5507 ft.atime = pull_long_date_full_timespec(pdata+8);
5509 /* write time. */
5510 ft.mtime = pull_long_date_full_timespec(pdata+16);
5512 /* change time. */
5513 ft.ctime = pull_long_date_full_timespec(pdata+24);
5515 DEBUG(10, ("smb_set_file_basic_info: file %s\n",
5516 smb_fname_str_dbg(smb_fname)));
5518 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
5519 if (!NT_STATUS_IS_OK(status)) {
5520 return status;
5523 if (fsp->fsp_flags.modified) {
5524 trigger_write_time_update_immediate(fsp);
5526 return NT_STATUS_OK;
5529 /****************************************************************************
5530 Deal with SMB_INFO_STANDARD.
5531 ****************************************************************************/
5533 static NTSTATUS smb_set_info_standard(connection_struct *conn,
5534 const char *pdata,
5535 int total_data,
5536 files_struct *fsp,
5537 struct smb_filename *smb_fname)
5539 NTSTATUS status;
5540 struct smb_file_time ft;
5542 init_smb_file_time(&ft);
5544 if (total_data < 12) {
5545 return NT_STATUS_INVALID_PARAMETER;
5548 if (fsp == NULL) {
5549 return NT_STATUS_INVALID_HANDLE;
5552 /* create time */
5553 ft.create_time = time_t_to_full_timespec(srv_make_unix_date2(pdata));
5554 /* access time */
5555 ft.atime = time_t_to_full_timespec(srv_make_unix_date2(pdata+4));
5556 /* write time */
5557 ft.mtime = time_t_to_full_timespec(srv_make_unix_date2(pdata+8));
5559 DEBUG(10,("smb_set_info_standard: file %s\n",
5560 smb_fname_str_dbg(smb_fname)));
5562 status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES);
5563 if (!NT_STATUS_IS_OK(status)) {
5564 return status;
5567 status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
5568 if (!NT_STATUS_IS_OK(status)) {
5569 return status;
5572 if (fsp->fsp_flags.modified) {
5573 trigger_write_time_update_immediate(fsp);
5575 return NT_STATUS_OK;
5578 /****************************************************************************
5579 Deal with SMB_SET_FILE_ALLOCATION_INFO.
5580 ****************************************************************************/
5582 static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
5583 struct smb_request *req,
5584 const char *pdata,
5585 int total_data,
5586 files_struct *fsp,
5587 struct smb_filename *smb_fname)
5589 uint64_t allocation_size = 0;
5590 NTSTATUS status = NT_STATUS_OK;
5591 files_struct *new_fsp = NULL;
5593 if (!VALID_STAT(smb_fname->st)) {
5594 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5597 if (total_data < 8) {
5598 return NT_STATUS_INVALID_PARAMETER;
5601 allocation_size = (uint64_t)IVAL(pdata,0);
5602 allocation_size |= (((uint64_t)IVAL(pdata,4)) << 32);
5603 DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for "
5604 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
5605 (double)allocation_size));
5607 if (allocation_size) {
5608 allocation_size = smb_roundup(conn, allocation_size);
5611 DEBUG(10,("smb_set_file_allocation_info: file %s : setting new "
5612 "allocation size to %.0f\n", smb_fname_str_dbg(smb_fname),
5613 (double)allocation_size));
5615 if (fsp &&
5616 !fsp->fsp_flags.is_pathref &&
5617 fsp_get_io_fd(fsp) != -1)
5619 /* Open file handle. */
5620 if (!(fsp->access_mask & FILE_WRITE_DATA)) {
5621 return NT_STATUS_ACCESS_DENIED;
5624 /* Only change if needed. */
5625 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
5626 if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
5627 return map_nt_error_from_unix(errno);
5630 /* But always update the time. */
5632 * This is equivalent to a write. Ensure it's seen immediately
5633 * if there are no pending writes.
5635 trigger_write_time_update_immediate(fsp);
5636 return NT_STATUS_OK;
5639 /* Pathname or stat or directory file. */
5640 status = SMB_VFS_CREATE_FILE(
5641 conn, /* conn */
5642 req, /* req */
5643 smb_fname, /* fname */
5644 FILE_WRITE_DATA, /* access_mask */
5645 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5646 FILE_SHARE_DELETE),
5647 FILE_OPEN, /* create_disposition*/
5648 0, /* create_options */
5649 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
5650 0, /* oplock_request */
5651 NULL, /* lease */
5652 0, /* allocation_size */
5653 0, /* private_flags */
5654 NULL, /* sd */
5655 NULL, /* ea_list */
5656 &new_fsp, /* result */
5657 NULL, /* pinfo */
5658 NULL, NULL); /* create context */
5660 if (!NT_STATUS_IS_OK(status)) {
5661 /* NB. We check for open_was_deferred in the caller. */
5662 return status;
5665 /* Only change if needed. */
5666 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
5667 if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) {
5668 status = map_nt_error_from_unix(errno);
5669 close_file_free(req, &new_fsp, NORMAL_CLOSE);
5670 return status;
5674 /* Changing the allocation size should set the last mod time. */
5676 * This is equivalent to a write. Ensure it's seen immediately
5677 * if there are no pending writes.
5679 trigger_write_time_update_immediate(new_fsp);
5680 close_file_free(req, &new_fsp, NORMAL_CLOSE);
5681 return NT_STATUS_OK;
5684 /****************************************************************************
5685 Deal with SMB_SET_FILE_END_OF_FILE_INFO.
5686 ****************************************************************************/
5688 static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
5689 struct smb_request *req,
5690 const char *pdata,
5691 int total_data,
5692 files_struct *fsp,
5693 struct smb_filename *smb_fname,
5694 bool fail_after_createfile)
5696 off_t size;
5698 if (total_data < 8) {
5699 return NT_STATUS_INVALID_PARAMETER;
5702 size = IVAL(pdata,0);
5703 size |= (((off_t)IVAL(pdata,4)) << 32);
5704 DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for "
5705 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
5706 (double)size));
5708 return smb_set_file_size(conn, req,
5709 fsp,
5710 smb_fname,
5711 &smb_fname->st,
5712 size,
5713 fail_after_createfile);
5716 /****************************************************************************
5717 Allow a UNIX info mknod.
5718 ****************************************************************************/
5720 static NTSTATUS smb_unix_mknod(connection_struct *conn,
5721 const char *pdata,
5722 int total_data,
5723 const struct smb_filename *smb_fname)
5725 uint32_t file_type = IVAL(pdata,56);
5726 #if defined(HAVE_MAKEDEV)
5727 uint32_t dev_major = IVAL(pdata,60);
5728 uint32_t dev_minor = IVAL(pdata,68);
5729 #endif
5730 SMB_DEV_T dev = (SMB_DEV_T)0;
5731 uint32_t raw_unixmode = IVAL(pdata,84);
5732 NTSTATUS status;
5733 mode_t unixmode;
5734 int ret;
5735 struct smb_filename *parent_fname = NULL;
5736 struct smb_filename *base_name = NULL;
5738 if (total_data < 100) {
5739 return NT_STATUS_INVALID_PARAMETER;
5742 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
5743 PERM_NEW_FILE, &unixmode);
5744 if (!NT_STATUS_IS_OK(status)) {
5745 return status;
5748 #if defined(HAVE_MAKEDEV)
5749 dev = makedev(dev_major, dev_minor);
5750 #endif
5752 switch (file_type) {
5753 /* We can't create other objects here. */
5754 case UNIX_TYPE_FILE:
5755 case UNIX_TYPE_DIR:
5756 case UNIX_TYPE_SYMLINK:
5757 return NT_STATUS_ACCESS_DENIED;
5758 #if defined(S_IFIFO)
5759 case UNIX_TYPE_FIFO:
5760 unixmode |= S_IFIFO;
5761 break;
5762 #endif
5763 #if defined(S_IFSOCK)
5764 case UNIX_TYPE_SOCKET:
5765 unixmode |= S_IFSOCK;
5766 break;
5767 #endif
5768 #if defined(S_IFCHR)
5769 case UNIX_TYPE_CHARDEV:
5770 /* This is only allowed for root. */
5771 if (get_current_uid(conn) != sec_initial_uid()) {
5772 return NT_STATUS_ACCESS_DENIED;
5774 unixmode |= S_IFCHR;
5775 break;
5776 #endif
5777 #if defined(S_IFBLK)
5778 case UNIX_TYPE_BLKDEV:
5779 if (get_current_uid(conn) != sec_initial_uid()) {
5780 return NT_STATUS_ACCESS_DENIED;
5782 unixmode |= S_IFBLK;
5783 break;
5784 #endif
5785 default:
5786 return NT_STATUS_INVALID_PARAMETER;
5789 DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
5790 "%.0f mode 0%o for file %s\n", (double)dev,
5791 (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
5793 status = parent_pathref(talloc_tos(),
5794 conn->cwd_fsp,
5795 smb_fname,
5796 &parent_fname,
5797 &base_name);
5798 if (!NT_STATUS_IS_OK(status)) {
5799 return status;
5802 /* Ok - do the mknod. */
5803 ret = SMB_VFS_MKNODAT(conn,
5804 parent_fname->fsp,
5805 base_name,
5806 unixmode,
5807 dev);
5809 if (ret != 0) {
5810 TALLOC_FREE(parent_fname);
5811 return map_nt_error_from_unix(errno);
5814 /* If any of the other "set" calls fail we
5815 * don't want to end up with a half-constructed mknod.
5818 if (lp_inherit_permissions(SNUM(conn))) {
5819 inherit_access_posix_acl(conn,
5820 parent_fname->fsp,
5821 smb_fname,
5822 unixmode);
5824 TALLOC_FREE(parent_fname);
5826 return NT_STATUS_OK;
5829 /****************************************************************************
5830 Deal with SMB_SET_FILE_UNIX_BASIC.
5831 ****************************************************************************/
5833 static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
5834 struct smb_request *req,
5835 const char *pdata,
5836 int total_data,
5837 files_struct *fsp,
5838 struct smb_filename *smb_fname)
5840 struct smb_file_time ft;
5841 uint32_t raw_unixmode;
5842 mode_t unixmode;
5843 off_t size = 0;
5844 uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
5845 gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
5846 NTSTATUS status = NT_STATUS_OK;
5847 enum perm_type ptype;
5848 files_struct *all_fsps = NULL;
5849 bool modify_mtime = true;
5850 struct file_id id;
5851 SMB_STRUCT_STAT sbuf;
5853 init_smb_file_time(&ft);
5855 if (total_data < 100) {
5856 return NT_STATUS_INVALID_PARAMETER;
5859 if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
5860 IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
5861 size=IVAL(pdata,0); /* first 8 Bytes are size */
5862 size |= (((off_t)IVAL(pdata,4)) << 32);
5865 ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
5866 ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
5867 set_owner = (uid_t)IVAL(pdata,40);
5868 set_grp = (gid_t)IVAL(pdata,48);
5869 raw_unixmode = IVAL(pdata,84);
5871 if (VALID_STAT(smb_fname->st)) {
5872 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
5873 ptype = PERM_EXISTING_DIR;
5874 } else {
5875 ptype = PERM_EXISTING_FILE;
5877 } else {
5878 ptype = PERM_NEW_FILE;
5881 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
5882 ptype, &unixmode);
5883 if (!NT_STATUS_IS_OK(status)) {
5884 return status;
5887 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
5888 "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
5889 smb_fname_str_dbg(smb_fname), (double)size,
5890 (unsigned int)set_owner, (unsigned int)set_grp,
5891 (int)raw_unixmode));
5893 sbuf = smb_fname->st;
5895 if (!VALID_STAT(sbuf)) {
5897 * The only valid use of this is to create character and block
5898 * devices, and named pipes. This is deprecated (IMHO) and
5899 * a new info level should be used for mknod. JRA.
5902 return smb_unix_mknod(conn,
5903 pdata,
5904 total_data,
5905 smb_fname);
5908 #if 1
5909 /* Horrible backwards compatibility hack as an old server bug
5910 * allowed a CIFS client bug to remain unnoticed :-(. JRA.
5911 * */
5913 if (!size) {
5914 size = get_file_size_stat(&sbuf);
5916 #endif
5919 * Deal with the UNIX specific mode set.
5922 if (raw_unixmode != SMB_MODE_NO_CHANGE) {
5923 int ret;
5925 if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
5926 DBG_WARNING("Can't set mode on symlink %s\n",
5927 smb_fname_str_dbg(smb_fname));
5928 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5931 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
5932 "setting mode 0%o for file %s\n",
5933 (unsigned int)unixmode,
5934 smb_fname_str_dbg(smb_fname)));
5935 ret = SMB_VFS_FCHMOD(fsp, unixmode);
5936 if (ret != 0) {
5937 return map_nt_error_from_unix(errno);
5942 * Deal with the UNIX specific uid set.
5945 if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
5946 (sbuf.st_ex_uid != set_owner)) {
5947 int ret;
5949 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
5950 "changing owner %u for path %s\n",
5951 (unsigned int)set_owner,
5952 smb_fname_str_dbg(smb_fname)));
5954 if (fsp &&
5955 !fsp->fsp_flags.is_pathref &&
5956 fsp_get_io_fd(fsp) != -1)
5958 ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
5959 } else {
5961 * UNIX extensions calls must always operate
5962 * on symlinks.
5964 ret = SMB_VFS_LCHOWN(conn, smb_fname,
5965 set_owner, (gid_t)-1);
5968 if (ret != 0) {
5969 status = map_nt_error_from_unix(errno);
5970 return status;
5975 * Deal with the UNIX specific gid set.
5978 if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
5979 (sbuf.st_ex_gid != set_grp)) {
5980 int ret;
5982 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
5983 "changing group %u for file %s\n",
5984 (unsigned int)set_grp,
5985 smb_fname_str_dbg(smb_fname)));
5986 if (fsp &&
5987 !fsp->fsp_flags.is_pathref &&
5988 fsp_get_io_fd(fsp) != -1)
5990 ret = SMB_VFS_FCHOWN(fsp, (uid_t)-1, set_grp);
5991 } else {
5993 * UNIX extensions calls must always operate
5994 * on symlinks.
5996 ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
5997 set_grp);
5999 if (ret != 0) {
6000 status = map_nt_error_from_unix(errno);
6001 return status;
6005 /* Deal with any size changes. */
6007 if (S_ISREG(sbuf.st_ex_mode)) {
6008 status = smb_set_file_size(conn, req,
6009 fsp,
6010 smb_fname,
6011 &sbuf,
6012 size,
6013 false);
6014 if (!NT_STATUS_IS_OK(status)) {
6015 return status;
6019 /* Deal with any time changes. */
6020 if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
6021 /* No change, don't cancel anything. */
6022 return status;
6025 id = vfs_file_id_from_sbuf(conn, &sbuf);
6026 for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
6027 all_fsps = file_find_di_next(all_fsps, true)) {
6029 * We're setting the time explicitly for UNIX.
6030 * Cancel any pending changes over all handles.
6032 all_fsps->fsp_flags.update_write_time_on_close = false;
6033 TALLOC_FREE(all_fsps->update_write_time_event);
6037 * Override the "setting_write_time"
6038 * parameter here as it almost does what
6039 * we need. Just remember if we modified
6040 * mtime and send the notify ourselves.
6042 if (is_omit_timespec(&ft.mtime)) {
6043 modify_mtime = false;
6046 status = smb_set_file_time(conn,
6047 fsp,
6048 smb_fname,
6049 &ft,
6050 false);
6051 if (modify_mtime) {
6052 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6053 FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
6055 return status;
6058 /****************************************************************************
6059 Deal with SMB_SET_FILE_UNIX_INFO2.
6060 ****************************************************************************/
6062 static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
6063 struct smb_request *req,
6064 const char *pdata,
6065 int total_data,
6066 files_struct *fsp,
6067 struct smb_filename *smb_fname)
6069 NTSTATUS status;
6070 uint32_t smb_fflags;
6071 uint32_t smb_fmask;
6073 if (total_data < 116) {
6074 return NT_STATUS_INVALID_PARAMETER;
6077 /* Start by setting all the fields that are common between UNIX_BASIC
6078 * and UNIX_INFO2.
6080 status = smb_set_file_unix_basic(conn, req, pdata, total_data,
6081 fsp, smb_fname);
6082 if (!NT_STATUS_IS_OK(status)) {
6083 return status;
6086 smb_fflags = IVAL(pdata, 108);
6087 smb_fmask = IVAL(pdata, 112);
6089 /* NB: We should only attempt to alter the file flags if the client
6090 * sends a non-zero mask.
6092 if (smb_fmask != 0) {
6093 int stat_fflags = 0;
6095 if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
6096 smb_fmask, &stat_fflags)) {
6097 /* Client asked to alter a flag we don't understand. */
6098 return NT_STATUS_INVALID_PARAMETER;
6101 if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
6102 DBG_WARNING("Can't change flags on symlink %s\n",
6103 smb_fname_str_dbg(smb_fname));
6104 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6106 if (SMB_VFS_FCHFLAGS(fsp, stat_fflags) != 0) {
6107 return map_nt_error_from_unix(errno);
6111 /* XXX: need to add support for changing the create_time here. You
6112 * can do this for paths on Darwin with setattrlist(2). The right way
6113 * to hook this up is probably by extending the VFS utimes interface.
6116 return NT_STATUS_OK;
6119 /****************************************************************************
6120 Create a directory with POSIX semantics.
6121 ****************************************************************************/
6123 static NTSTATUS smb_posix_mkdir(connection_struct *conn,
6124 struct smb_request *req,
6125 char **ppdata,
6126 int total_data,
6127 struct smb_filename *smb_fname,
6128 int *pdata_return_size)
6130 NTSTATUS status = NT_STATUS_OK;
6131 uint32_t raw_unixmode = 0;
6132 mode_t unixmode = (mode_t)0;
6133 files_struct *fsp = NULL;
6134 uint16_t info_level_return = 0;
6135 int info;
6136 char *pdata = *ppdata;
6137 struct smb2_create_blobs *posx = NULL;
6139 if (total_data < 18) {
6140 return NT_STATUS_INVALID_PARAMETER;
6143 raw_unixmode = IVAL(pdata,8);
6144 /* Next 4 bytes are not yet defined. */
6146 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6147 PERM_NEW_DIR, &unixmode);
6148 if (!NT_STATUS_IS_OK(status)) {
6149 return status;
6152 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
6153 if (!NT_STATUS_IS_OK(status)) {
6154 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
6155 nt_errstr(status));
6156 return status;
6159 DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
6160 smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
6162 status = SMB_VFS_CREATE_FILE(
6163 conn, /* conn */
6164 req, /* req */
6165 smb_fname, /* fname */
6166 FILE_READ_ATTRIBUTES, /* access_mask */
6167 FILE_SHARE_NONE, /* share_access */
6168 FILE_CREATE, /* create_disposition*/
6169 FILE_DIRECTORY_FILE, /* create_options */
6170 0, /* file_attributes */
6171 0, /* oplock_request */
6172 NULL, /* lease */
6173 0, /* allocation_size */
6174 0, /* private_flags */
6175 NULL, /* sd */
6176 NULL, /* ea_list */
6177 &fsp, /* result */
6178 &info, /* pinfo */
6179 posx, /* in_context_blobs */
6180 NULL); /* out_context_blobs */
6182 TALLOC_FREE(posx);
6184 if (NT_STATUS_IS_OK(status)) {
6185 close_file_free(req, &fsp, NORMAL_CLOSE);
6188 info_level_return = SVAL(pdata,16);
6190 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
6191 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
6192 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
6193 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
6194 } else {
6195 *pdata_return_size = 12;
6198 /* Realloc the data size */
6199 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
6200 if (*ppdata == NULL) {
6201 *pdata_return_size = 0;
6202 return NT_STATUS_NO_MEMORY;
6204 pdata = *ppdata;
6206 SSVAL(pdata,0,NO_OPLOCK_RETURN);
6207 SSVAL(pdata,2,0); /* No fnum. */
6208 SIVAL(pdata,4,info); /* Was directory created. */
6210 switch (info_level_return) {
6211 case SMB_QUERY_FILE_UNIX_BASIC:
6212 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
6213 SSVAL(pdata,10,0); /* Padding. */
6214 store_file_unix_basic(conn, pdata + 12, fsp,
6215 &smb_fname->st);
6216 break;
6217 case SMB_QUERY_FILE_UNIX_INFO2:
6218 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
6219 SSVAL(pdata,10,0); /* Padding. */
6220 store_file_unix_basic_info2(conn, pdata + 12, fsp,
6221 &smb_fname->st);
6222 break;
6223 default:
6224 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
6225 SSVAL(pdata,10,0); /* Padding. */
6226 break;
6229 return status;
6232 /****************************************************************************
6233 Open/Create a file with POSIX semantics.
6234 ****************************************************************************/
6236 #define SMB_O_RDONLY_MAPPING (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
6237 #define SMB_O_WRONLY_MAPPING (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA)
6239 static NTSTATUS smb_posix_open(connection_struct *conn,
6240 struct smb_request *req,
6241 char **ppdata,
6242 int total_data,
6243 struct smb_filename *smb_fname,
6244 int *pdata_return_size)
6246 bool extended_oplock_granted = False;
6247 char *pdata = *ppdata;
6248 uint32_t flags = 0;
6249 uint32_t wire_open_mode = 0;
6250 uint32_t raw_unixmode = 0;
6251 uint32_t attributes = 0;
6252 uint32_t create_disp = 0;
6253 uint32_t access_mask = 0;
6254 uint32_t create_options = FILE_NON_DIRECTORY_FILE;
6255 NTSTATUS status = NT_STATUS_OK;
6256 mode_t unixmode = (mode_t)0;
6257 files_struct *fsp = NULL;
6258 int oplock_request = 0;
6259 int info = 0;
6260 uint16_t info_level_return = 0;
6261 struct smb2_create_blobs *posx = NULL;
6263 if (total_data < 18) {
6264 return NT_STATUS_INVALID_PARAMETER;
6267 flags = IVAL(pdata,0);
6268 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
6269 if (oplock_request) {
6270 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
6273 wire_open_mode = IVAL(pdata,4);
6275 if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
6276 return smb_posix_mkdir(conn, req,
6277 ppdata,
6278 total_data,
6279 smb_fname,
6280 pdata_return_size);
6283 switch (wire_open_mode & SMB_ACCMODE) {
6284 case SMB_O_RDONLY:
6285 access_mask = SMB_O_RDONLY_MAPPING;
6286 break;
6287 case SMB_O_WRONLY:
6288 access_mask = SMB_O_WRONLY_MAPPING;
6289 break;
6290 case SMB_O_RDWR:
6291 access_mask = (SMB_O_RDONLY_MAPPING|
6292 SMB_O_WRONLY_MAPPING);
6293 break;
6294 default:
6295 DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
6296 (unsigned int)wire_open_mode ));
6297 return NT_STATUS_INVALID_PARAMETER;
6300 wire_open_mode &= ~SMB_ACCMODE;
6302 /* First take care of O_CREAT|O_EXCL interactions. */
6303 switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
6304 case (SMB_O_CREAT | SMB_O_EXCL):
6305 /* File exists fail. File not exist create. */
6306 create_disp = FILE_CREATE;
6307 break;
6308 case SMB_O_CREAT:
6309 /* File exists open. File not exist create. */
6310 create_disp = FILE_OPEN_IF;
6311 break;
6312 case SMB_O_EXCL:
6313 /* O_EXCL on its own without O_CREAT is undefined.
6314 We deliberately ignore it as some versions of
6315 Linux CIFSFS can send a bare O_EXCL on the
6316 wire which other filesystems in the kernel
6317 ignore. See bug 9519 for details. */
6319 /* Fallthrough. */
6321 case 0:
6322 /* File exists open. File not exist fail. */
6323 create_disp = FILE_OPEN;
6324 break;
6325 default:
6326 DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
6327 (unsigned int)wire_open_mode ));
6328 return NT_STATUS_INVALID_PARAMETER;
6331 /* Next factor in the effects of O_TRUNC. */
6332 wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);
6334 if (wire_open_mode & SMB_O_TRUNC) {
6335 switch (create_disp) {
6336 case FILE_CREATE:
6337 /* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
6338 /* Leave create_disp alone as
6339 (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
6341 /* File exists fail. File not exist create. */
6342 break;
6343 case FILE_OPEN_IF:
6344 /* SMB_O_CREAT | SMB_O_TRUNC */
6345 /* File exists overwrite. File not exist create. */
6346 create_disp = FILE_OVERWRITE_IF;
6347 break;
6348 case FILE_OPEN:
6349 /* SMB_O_TRUNC */
6350 /* File exists overwrite. File not exist fail. */
6351 create_disp = FILE_OVERWRITE;
6352 break;
6353 default:
6354 /* Cannot get here. */
6355 smb_panic("smb_posix_open: logic error");
6356 return NT_STATUS_INVALID_PARAMETER;
6360 raw_unixmode = IVAL(pdata,8);
6361 /* Next 4 bytes are not yet defined. */
6363 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6364 (VALID_STAT(smb_fname->st) ?
6365 PERM_EXISTING_FILE : PERM_NEW_FILE),
6366 &unixmode);
6368 if (!NT_STATUS_IS_OK(status)) {
6369 return status;
6372 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
6373 if (!NT_STATUS_IS_OK(status)) {
6374 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
6375 nt_errstr(status));
6376 return status;
6379 if (wire_open_mode & SMB_O_SYNC) {
6380 create_options |= FILE_WRITE_THROUGH;
6382 if (wire_open_mode & SMB_O_APPEND) {
6383 access_mask |= FILE_APPEND_DATA;
6385 if (wire_open_mode & SMB_O_DIRECT) {
6386 attributes |= FILE_FLAG_NO_BUFFERING;
6389 if ((wire_open_mode & SMB_O_DIRECTORY) ||
6390 VALID_STAT_OF_DIR(smb_fname->st)) {
6391 if (access_mask != SMB_O_RDONLY_MAPPING) {
6392 return NT_STATUS_FILE_IS_A_DIRECTORY;
6394 create_options &= ~FILE_NON_DIRECTORY_FILE;
6395 create_options |= FILE_DIRECTORY_FILE;
6398 DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
6399 smb_fname_str_dbg(smb_fname),
6400 (unsigned int)wire_open_mode,
6401 (unsigned int)unixmode ));
6403 status = SMB_VFS_CREATE_FILE(
6404 conn, /* conn */
6405 req, /* req */
6406 smb_fname, /* fname */
6407 access_mask, /* access_mask */
6408 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6409 FILE_SHARE_DELETE),
6410 create_disp, /* create_disposition*/
6411 create_options, /* create_options */
6412 attributes, /* file_attributes */
6413 oplock_request, /* oplock_request */
6414 NULL, /* lease */
6415 0, /* allocation_size */
6416 0, /* private_flags */
6417 NULL, /* sd */
6418 NULL, /* ea_list */
6419 &fsp, /* result */
6420 &info, /* pinfo */
6421 posx, /* in_context_blobs */
6422 NULL); /* out_context_blobs */
6424 TALLOC_FREE(posx);
6426 if (!NT_STATUS_IS_OK(status)) {
6427 return status;
6430 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
6431 extended_oplock_granted = True;
6434 if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
6435 extended_oplock_granted = True;
6438 info_level_return = SVAL(pdata,16);
6440 /* Allocate the correct return size. */
6442 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
6443 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
6444 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
6445 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
6446 } else {
6447 *pdata_return_size = 12;
6450 /* Realloc the data size */
6451 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
6452 if (*ppdata == NULL) {
6453 close_file_free(req, &fsp, ERROR_CLOSE);
6454 *pdata_return_size = 0;
6455 return NT_STATUS_NO_MEMORY;
6457 pdata = *ppdata;
6459 if (extended_oplock_granted) {
6460 if (flags & REQUEST_BATCH_OPLOCK) {
6461 SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
6462 } else {
6463 SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
6465 } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
6466 SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
6467 } else {
6468 SSVAL(pdata,0,NO_OPLOCK_RETURN);
6471 SSVAL(pdata,2,fsp->fnum);
6472 SIVAL(pdata,4,info); /* Was file created etc. */
6474 switch (info_level_return) {
6475 case SMB_QUERY_FILE_UNIX_BASIC:
6476 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
6477 SSVAL(pdata,10,0); /* padding. */
6478 store_file_unix_basic(conn, pdata + 12, fsp,
6479 &smb_fname->st);
6480 break;
6481 case SMB_QUERY_FILE_UNIX_INFO2:
6482 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
6483 SSVAL(pdata,10,0); /* padding. */
6484 store_file_unix_basic_info2(conn, pdata + 12, fsp,
6485 &smb_fname->st);
6486 break;
6487 default:
6488 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
6489 SSVAL(pdata,10,0); /* padding. */
6490 break;
6492 return NT_STATUS_OK;
6495 /****************************************************************************
6496 Delete a file with POSIX semantics.
6497 ****************************************************************************/
6499 static NTSTATUS smb_posix_unlink(connection_struct *conn,
6500 struct smb_request *req,
6501 const char *pdata,
6502 int total_data,
6503 struct smb_filename *smb_fname)
6505 NTSTATUS status = NT_STATUS_OK;
6506 files_struct *fsp = NULL;
6507 uint16_t flags = 0;
6508 char del = 1;
6509 int info = 0;
6510 int create_options = 0;
6511 struct share_mode_lock *lck = NULL;
6512 bool other_nonposix_opens;
6513 struct smb2_create_blobs *posx = NULL;
6515 if (total_data < 2) {
6516 return NT_STATUS_INVALID_PARAMETER;
6519 flags = SVAL(pdata,0);
6521 if (!VALID_STAT(smb_fname->st)) {
6522 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6525 if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
6526 !VALID_STAT_OF_DIR(smb_fname->st)) {
6527 return NT_STATUS_NOT_A_DIRECTORY;
6530 DEBUG(10,("smb_posix_unlink: %s %s\n",
6531 (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
6532 smb_fname_str_dbg(smb_fname)));
6534 if (VALID_STAT_OF_DIR(smb_fname->st)) {
6535 create_options |= FILE_DIRECTORY_FILE;
6538 status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
6539 if (!NT_STATUS_IS_OK(status)) {
6540 DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
6541 nt_errstr(status));
6542 return status;
6545 status = SMB_VFS_CREATE_FILE(
6546 conn, /* conn */
6547 req, /* req */
6548 smb_fname, /* fname */
6549 DELETE_ACCESS, /* access_mask */
6550 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6551 FILE_SHARE_DELETE),
6552 FILE_OPEN, /* create_disposition*/
6553 create_options, /* create_options */
6554 0, /* file_attributes */
6555 0, /* oplock_request */
6556 NULL, /* lease */
6557 0, /* allocation_size */
6558 0, /* private_flags */
6559 NULL, /* sd */
6560 NULL, /* ea_list */
6561 &fsp, /* result */
6562 &info, /* pinfo */
6563 posx, /* in_context_blobs */
6564 NULL); /* out_context_blobs */
6566 TALLOC_FREE(posx);
6568 if (!NT_STATUS_IS_OK(status)) {
6569 return status;
6573 * Don't lie to client. If we can't really delete due to
6574 * non-POSIX opens return SHARING_VIOLATION.
6577 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6578 if (lck == NULL) {
6579 DEBUG(0, ("smb_posix_unlink: Could not get share mode "
6580 "lock for file %s\n", fsp_str_dbg(fsp)));
6581 close_file_free(req, &fsp, NORMAL_CLOSE);
6582 return NT_STATUS_INVALID_PARAMETER;
6585 other_nonposix_opens = has_other_nonposix_opens(lck, fsp);
6586 if (other_nonposix_opens) {
6587 /* Fail with sharing violation. */
6588 TALLOC_FREE(lck);
6589 close_file_free(req, &fsp, NORMAL_CLOSE);
6590 return NT_STATUS_SHARING_VIOLATION;
6594 * Set the delete on close.
6596 status = smb_set_file_disposition_info(conn,
6597 &del,
6599 fsp,
6600 smb_fname);
6602 TALLOC_FREE(lck);
6604 if (!NT_STATUS_IS_OK(status)) {
6605 close_file_free(req, &fsp, NORMAL_CLOSE);
6606 return status;
6608 return close_file_free(req, &fsp, NORMAL_CLOSE);
6611 static NTSTATUS smbd_do_posix_setfilepathinfo(struct connection_struct *conn,
6612 struct smb_request *req,
6613 TALLOC_CTX *mem_ctx,
6614 uint16_t info_level,
6615 struct smb_filename *smb_fname,
6616 files_struct *fsp,
6617 char **ppdata,
6618 int total_data,
6619 int *ret_data_size)
6621 char *pdata = *ppdata;
6622 NTSTATUS status = NT_STATUS_OK;
6623 int data_return_size = 0;
6625 *ret_data_size = 0;
6627 if (!CAN_WRITE(conn)) {
6628 /* Allow POSIX opens. The open path will deny
6629 * any non-readonly opens. */
6630 if (info_level != SMB_POSIX_PATH_OPEN) {
6631 return NT_STATUS_DOS(ERRSRV, ERRaccess);
6635 DBG_DEBUG("file=%s (%s) info_level=%d totdata=%d\n",
6636 smb_fname_str_dbg(smb_fname),
6637 fsp_fnum_dbg(fsp),
6638 info_level,
6639 total_data);
6641 switch (info_level) {
6642 case SMB_SET_FILE_UNIX_BASIC:
6644 status = smb_set_file_unix_basic(conn, req,
6645 pdata,
6646 total_data,
6647 fsp,
6648 smb_fname);
6649 break;
6652 case SMB_SET_FILE_UNIX_INFO2:
6654 status = smb_set_file_unix_info2(conn, req,
6655 pdata,
6656 total_data,
6657 fsp,
6658 smb_fname);
6659 break;
6662 case SMB_SET_FILE_UNIX_LINK:
6664 if (smb_fname == NULL) {
6665 /* We must have a pathname for this. */
6666 return NT_STATUS_INVALID_LEVEL;
6668 status = smb_set_file_unix_link(conn, req, pdata,
6669 total_data, smb_fname);
6670 break;
6673 case SMB_SET_FILE_UNIX_HLINK:
6675 if (smb_fname == NULL) {
6676 /* We must have a pathname for this. */
6677 return NT_STATUS_INVALID_LEVEL;
6679 status = smb_set_file_unix_hlink(conn, req,
6680 pdata, total_data,
6681 smb_fname);
6682 break;
6685 #if defined(HAVE_POSIX_ACLS)
6686 case SMB_SET_POSIX_ACL:
6688 status = smb_set_posix_acl(conn,
6689 req,
6690 pdata,
6691 total_data,
6692 fsp,
6693 smb_fname);
6694 break;
6696 #endif
6698 #if defined(WITH_SMB1SERVER)
6699 case SMB_SET_POSIX_LOCK:
6701 if (fsp == NULL) {
6702 return NT_STATUS_INVALID_LEVEL;
6704 status = smb_set_posix_lock(conn, req,
6705 pdata, total_data, fsp);
6706 break;
6708 #endif
6710 case SMB_POSIX_PATH_OPEN:
6712 if (smb_fname == NULL) {
6713 /* We must have a pathname for this. */
6714 return NT_STATUS_INVALID_LEVEL;
6717 status = smb_posix_open(conn, req,
6718 ppdata,
6719 total_data,
6720 smb_fname,
6721 &data_return_size);
6722 break;
6725 case SMB_POSIX_PATH_UNLINK:
6727 if (smb_fname == NULL) {
6728 /* We must have a pathname for this. */
6729 return NT_STATUS_INVALID_LEVEL;
6732 status = smb_posix_unlink(conn, req,
6733 pdata,
6734 total_data,
6735 smb_fname);
6736 break;
6739 default:
6740 return NT_STATUS_INVALID_LEVEL;
6743 if (!NT_STATUS_IS_OK(status)) {
6744 return status;
6747 *ret_data_size = data_return_size;
6748 return NT_STATUS_OK;
6751 NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
6752 struct smb_request *req,
6753 TALLOC_CTX *mem_ctx,
6754 uint16_t info_level,
6755 files_struct *fsp,
6756 struct smb_filename *smb_fname,
6757 char **ppdata, int total_data,
6758 int *ret_data_size)
6760 char *pdata = *ppdata;
6761 NTSTATUS status = NT_STATUS_OK;
6762 int data_return_size = 0;
6764 if (INFO_LEVEL_IS_UNIX(info_level)) {
6765 if (!lp_smb1_unix_extensions()) {
6766 return NT_STATUS_INVALID_LEVEL;
6768 if (!req->posix_pathnames) {
6769 return NT_STATUS_INVALID_LEVEL;
6771 status = smbd_do_posix_setfilepathinfo(conn,
6772 req,
6773 req,
6774 info_level,
6775 smb_fname,
6776 fsp,
6777 ppdata,
6778 total_data,
6779 &data_return_size);
6780 if (!NT_STATUS_IS_OK(status)) {
6781 return status;
6783 *ret_data_size = data_return_size;
6784 return NT_STATUS_OK;
6787 *ret_data_size = 0;
6789 DEBUG(3,("smbd_do_setfilepathinfo: %s (%s) info_level=%d "
6790 "totdata=%d\n", smb_fname_str_dbg(smb_fname),
6791 fsp_fnum_dbg(fsp),
6792 info_level, total_data));
6794 switch (info_level) {
6796 case SMB_INFO_STANDARD:
6798 status = smb_set_info_standard(conn,
6799 pdata,
6800 total_data,
6801 fsp,
6802 smb_fname);
6803 break;
6806 case SMB_INFO_SET_EA:
6808 status = smb_info_set_ea(conn,
6809 pdata,
6810 total_data,
6811 fsp,
6812 smb_fname);
6813 break;
6816 case SMB_SET_FILE_BASIC_INFO:
6817 case SMB_FILE_BASIC_INFORMATION:
6819 status = smb_set_file_basic_info(conn,
6820 pdata,
6821 total_data,
6822 fsp,
6823 smb_fname);
6824 break;
6827 case SMB_FILE_ALLOCATION_INFORMATION:
6828 case SMB_SET_FILE_ALLOCATION_INFO:
6830 status = smb_set_file_allocation_info(conn, req,
6831 pdata,
6832 total_data,
6833 fsp,
6834 smb_fname);
6835 break;
6838 case SMB_FILE_END_OF_FILE_INFORMATION:
6839 case SMB_SET_FILE_END_OF_FILE_INFO:
6842 * XP/Win7 both fail after the createfile with
6843 * SMB_SET_FILE_END_OF_FILE_INFO but not
6844 * SMB_FILE_END_OF_FILE_INFORMATION (pass-through).
6845 * The level is known here, so pass it down
6846 * appropriately.
6848 bool should_fail =
6849 (info_level == SMB_SET_FILE_END_OF_FILE_INFO);
6851 status = smb_set_file_end_of_file_info(conn, req,
6852 pdata,
6853 total_data,
6854 fsp,
6855 smb_fname,
6856 should_fail);
6857 break;
6860 case SMB_FILE_DISPOSITION_INFORMATION:
6861 case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
6863 #if 0
6864 /* JRA - We used to just ignore this on a path ?
6865 * Shouldn't this be invalid level on a pathname
6866 * based call ?
6868 if (tran_call != TRANSACT2_SETFILEINFO) {
6869 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
6871 #endif
6872 status = smb_set_file_disposition_info(conn,
6873 pdata,
6874 total_data,
6875 fsp,
6876 smb_fname);
6877 break;
6880 case SMB_FILE_POSITION_INFORMATION:
6882 status = smb_file_position_information(conn,
6883 pdata,
6884 total_data,
6885 fsp);
6886 break;
6889 case SMB_FILE_FULL_EA_INFORMATION:
6891 status = smb_set_file_full_ea_info(conn,
6892 pdata,
6893 total_data,
6894 fsp);
6895 break;
6898 /* From tridge Samba4 :
6899 * MODE_INFORMATION in setfileinfo (I have no
6900 * idea what "mode information" on a file is - it takes a value of 0,
6901 * 2, 4 or 6. What could it be?).
6904 case SMB_FILE_MODE_INFORMATION:
6906 status = smb_file_mode_information(conn,
6907 pdata,
6908 total_data);
6909 break;
6912 /* [MS-SMB2] 3.3.5.21.1 states we MUST fail with STATUS_NOT_SUPPORTED. */
6913 case SMB_FILE_VALID_DATA_LENGTH_INFORMATION:
6914 case SMB_FILE_SHORT_NAME_INFORMATION:
6915 return NT_STATUS_NOT_SUPPORTED;
6917 case SMB_FILE_RENAME_INFORMATION:
6919 status = smb_file_rename_information(conn, req,
6920 pdata, total_data,
6921 fsp, smb_fname);
6922 break;
6925 case SMB2_FILE_RENAME_INFORMATION_INTERNAL:
6927 /* SMB2 rename information. */
6928 status = smb2_file_rename_information(conn, req,
6929 pdata, total_data,
6930 fsp, smb_fname);
6931 break;
6934 case SMB_FILE_LINK_INFORMATION:
6936 status = smb_file_link_information(conn, req,
6937 pdata, total_data,
6938 fsp, smb_fname);
6939 break;
6942 default:
6943 return NT_STATUS_INVALID_LEVEL;
6946 if (!NT_STATUS_IS_OK(status)) {
6947 return status;
6950 *ret_data_size = data_return_size;
6951 return NT_STATUS_OK;