ldb: version 1.1.20
[Samba.git] / source3 / smbd / trans2.c
blob16498b36e56978bea4edb1ddb54cc31bb1ad70e7
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 "version.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "../libcli/auth/libcli_auth.h"
33 #include "../librpc/gen_ndr/xattr.h"
34 #include "../librpc/gen_ndr/ndr_security.h"
35 #include "../librpc/gen_ndr/open_files.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"
45 #define DIR_ENTRY_SAFETY_MARGIN 4096
47 static char *store_file_unix_basic(connection_struct *conn,
48 char *pdata,
49 files_struct *fsp,
50 const SMB_STRUCT_STAT *psbuf);
52 static char *store_file_unix_basic_info2(connection_struct *conn,
53 char *pdata,
54 files_struct *fsp,
55 const SMB_STRUCT_STAT *psbuf);
57 /********************************************************************
58 The canonical "check access" based on object handle or path function.
59 ********************************************************************/
61 NTSTATUS check_access(connection_struct *conn,
62 files_struct *fsp,
63 const struct smb_filename *smb_fname,
64 uint32_t access_mask)
66 if (fsp) {
67 if (!(fsp->access_mask & access_mask)) {
68 return NT_STATUS_ACCESS_DENIED;
70 } else {
71 NTSTATUS status = smbd_check_access_rights(conn,
72 smb_fname,
73 false,
74 access_mask);
75 if (!NT_STATUS_IS_OK(status)) {
76 return status;
79 return NT_STATUS_OK;
82 /********************************************************************
83 Roundup a value to the nearest allocation roundup size boundary.
84 Only do this for Windows clients.
85 ********************************************************************/
87 uint64_t smb_roundup(connection_struct *conn, uint64_t val)
89 uint64_t rval = lp_allocation_roundup_size(SNUM(conn));
91 /* Only roundup for Windows clients. */
92 enum remote_arch_types ra_type = get_remote_arch();
93 if (rval && (ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
94 val = SMB_ROUNDUP(val,rval);
96 return val;
99 /********************************************************************
100 Create a 64 bit FileIndex. If the file is on the same device as
101 the root of the share, just return the 64-bit inode. If it isn't,
102 mangle as we used to do.
103 ********************************************************************/
105 uint64_t get_FileIndex(connection_struct *conn, const SMB_STRUCT_STAT *psbuf)
107 uint64_t file_index;
108 if (conn->base_share_dev == psbuf->st_ex_dev) {
109 return (uint64_t)psbuf->st_ex_ino;
111 file_index = ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */
112 file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */
113 return file_index;
116 /****************************************************************************
117 Utility functions for dealing with extended attributes.
118 ****************************************************************************/
120 /****************************************************************************
121 Refuse to allow clients to overwrite our private xattrs.
122 ****************************************************************************/
124 bool samba_private_attr_name(const char *unix_ea_name)
126 static const char * const prohibited_ea_names[] = {
127 SAMBA_POSIX_INHERITANCE_EA_NAME,
128 SAMBA_XATTR_DOS_ATTRIB,
129 SAMBA_XATTR_MARKER,
130 XATTR_NTACL_NAME,
131 NULL
134 int i;
136 for (i = 0; prohibited_ea_names[i]; i++) {
137 if (strequal( prohibited_ea_names[i], unix_ea_name))
138 return true;
140 if (strncasecmp_m(unix_ea_name, SAMBA_XATTR_DOSSTREAM_PREFIX,
141 strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) == 0) {
142 return true;
144 return false;
147 /****************************************************************************
148 Get one EA value. Fill in a struct ea_struct.
149 ****************************************************************************/
151 NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn,
152 files_struct *fsp, const char *fname,
153 const char *ea_name, struct ea_struct *pea)
155 /* Get the value of this xattr. Max size is 64k. */
156 size_t attr_size = 256;
157 char *val = NULL;
158 ssize_t sizeret;
160 again:
162 val = talloc_realloc(mem_ctx, val, char, attr_size);
163 if (!val) {
164 return NT_STATUS_NO_MEMORY;
167 if (fsp && fsp->fh->fd != -1) {
168 sizeret = SMB_VFS_FGETXATTR(fsp, ea_name, val, attr_size);
169 } else {
170 sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size);
173 if (sizeret == -1 && errno == ERANGE && attr_size != 65536) {
174 attr_size = 65536;
175 goto again;
178 if (sizeret == -1) {
179 return map_nt_error_from_unix(errno);
182 DEBUG(10,("get_ea_value: EA %s is of length %u\n", ea_name, (unsigned int)sizeret));
183 dump_data(10, (uint8 *)val, sizeret);
185 pea->flags = 0;
186 if (strnequal(ea_name, "user.", 5)) {
187 pea->name = talloc_strdup(mem_ctx, &ea_name[5]);
188 } else {
189 pea->name = talloc_strdup(mem_ctx, ea_name);
191 if (pea->name == NULL) {
192 TALLOC_FREE(val);
193 return NT_STATUS_NO_MEMORY;
195 pea->value.data = (unsigned char *)val;
196 pea->value.length = (size_t)sizeret;
197 return NT_STATUS_OK;
200 NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
201 files_struct *fsp, const char *fname,
202 char ***pnames, size_t *pnum_names)
204 /* Get a list of all xattrs. Max namesize is 64k. */
205 size_t ea_namelist_size = 1024;
206 char *ea_namelist = NULL;
208 char *p;
209 char **names, **tmp;
210 size_t num_names;
211 ssize_t sizeret = -1;
213 if (!lp_ea_support(SNUM(conn))) {
214 if (pnames) {
215 *pnames = NULL;
217 *pnum_names = 0;
218 return NT_STATUS_OK;
222 * TALLOC the result early to get the talloc hierarchy right.
225 names = talloc_array(mem_ctx, char *, 1);
226 if (names == NULL) {
227 DEBUG(0, ("talloc failed\n"));
228 return NT_STATUS_NO_MEMORY;
231 while (ea_namelist_size <= 65536) {
233 ea_namelist = talloc_realloc(
234 names, ea_namelist, char, ea_namelist_size);
235 if (ea_namelist == NULL) {
236 DEBUG(0, ("talloc failed\n"));
237 TALLOC_FREE(names);
238 return NT_STATUS_NO_MEMORY;
241 if (fsp && fsp->fh->fd != -1) {
242 sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
243 ea_namelist_size);
244 } else {
245 sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist,
246 ea_namelist_size);
249 if ((sizeret == -1) && (errno == ERANGE)) {
250 ea_namelist_size *= 2;
252 else {
253 break;
257 if (sizeret == -1) {
258 TALLOC_FREE(names);
259 return map_nt_error_from_unix(errno);
262 DEBUG(10, ("%s: ea_namelist size = %u\n",
263 __func__, (unsigned int)sizeret));
265 if (sizeret == 0) {
266 TALLOC_FREE(names);
267 if (pnames) {
268 *pnames = NULL;
270 *pnum_names = 0;
271 return NT_STATUS_OK;
275 * Ensure the result is 0-terminated
278 if (ea_namelist[sizeret-1] != '\0') {
279 TALLOC_FREE(names);
280 return NT_STATUS_INTERNAL_ERROR;
284 * count the names
286 num_names = 0;
288 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
289 num_names += 1;
292 tmp = talloc_realloc(mem_ctx, names, char *, num_names);
293 if (tmp == NULL) {
294 DEBUG(0, ("talloc failed\n"));
295 TALLOC_FREE(names);
296 return NT_STATUS_NO_MEMORY;
299 names = tmp;
300 num_names = 0;
302 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
303 names[num_names++] = p;
306 if (pnames) {
307 *pnames = names;
308 } else {
309 TALLOC_FREE(names);
311 *pnum_names = num_names;
312 return NT_STATUS_OK;
315 /****************************************************************************
316 Return a linked list of the total EA's. Plus the total size
317 ****************************************************************************/
319 static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
320 const char *fname, size_t *pea_total_len, struct ea_list **ea_list)
322 /* Get a list of all xattrs. Max namesize is 64k. */
323 size_t i, num_names;
324 char **names;
325 struct ea_list *ea_list_head = NULL;
326 NTSTATUS status;
328 *pea_total_len = 0;
329 *ea_list = NULL;
331 status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
332 &names, &num_names);
334 if (!NT_STATUS_IS_OK(status)) {
335 return status;
338 if (num_names == 0) {
339 *ea_list = NULL;
340 return NT_STATUS_OK;
343 for (i=0; i<num_names; i++) {
344 struct ea_list *listp;
345 fstring dos_ea_name;
347 if (strnequal(names[i], "system.", 7)
348 || samba_private_attr_name(names[i]))
349 continue;
352 * Filter out any underlying POSIX EA names
353 * that a Windows client can't handle.
355 if (!lp_posix_pathnames() &&
356 is_invalid_windows_ea_name(names[i])) {
357 continue;
360 listp = talloc(mem_ctx, struct ea_list);
361 if (listp == NULL) {
362 return NT_STATUS_NO_MEMORY;
365 status = get_ea_value(listp, conn, fsp,
366 fname, names[i],
367 &listp->ea);
369 if (!NT_STATUS_IS_OK(status)) {
370 TALLOC_FREE(listp);
371 return status;
374 if (listp->ea.value.length == 0) {
376 * We can never return a zero length EA.
377 * Windows reports the EA's as corrupted.
379 TALLOC_FREE(listp);
380 continue;
383 push_ascii_fstring(dos_ea_name, listp->ea.name);
385 *pea_total_len +=
386 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
388 DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len "
389 "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
390 (unsigned int)listp->ea.value.length));
392 DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
396 /* Add on 4 for total length. */
397 if (*pea_total_len) {
398 *pea_total_len += 4;
401 DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
402 (unsigned int)*pea_total_len));
404 *ea_list = ea_list_head;
405 return NT_STATUS_OK;
408 static NTSTATUS get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
409 const struct smb_filename *smb_fname, size_t *pea_total_len, struct ea_list **ea_list)
411 *pea_total_len = 0;
412 *ea_list = NULL;
414 if (!lp_ea_support(SNUM(conn))) {
415 return NT_STATUS_OK;
418 if (is_ntfs_stream_smb_fname(smb_fname)) {
419 return NT_STATUS_INVALID_PARAMETER;
422 return get_ea_list_from_file_path(mem_ctx, conn, fsp, smb_fname->base_name, pea_total_len, ea_list);
425 /****************************************************************************
426 Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer
427 that was filled.
428 ****************************************************************************/
430 static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
431 connection_struct *conn, struct ea_list *ea_list)
433 unsigned int ret_data_size = 4;
434 char *p = pdata;
436 SMB_ASSERT(total_data_size >= 4);
438 if (!lp_ea_support(SNUM(conn))) {
439 SIVAL(pdata,4,0);
440 return 4;
443 for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
444 size_t dos_namelen;
445 fstring dos_ea_name;
446 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
447 dos_namelen = strlen(dos_ea_name);
448 if (dos_namelen > 255 || dos_namelen == 0) {
449 break;
451 if (ea_list->ea.value.length > 65535) {
452 break;
454 if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
455 break;
458 /* We know we have room. */
459 SCVAL(p,0,ea_list->ea.flags);
460 SCVAL(p,1,dos_namelen);
461 SSVAL(p,2,ea_list->ea.value.length);
462 strlcpy(p+4, dos_ea_name, dos_namelen+1);
463 memcpy( p + 4 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
465 total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
466 p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
469 ret_data_size = PTR_DIFF(p, pdata);
470 DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
471 SIVAL(pdata,0,ret_data_size);
472 return ret_data_size;
475 static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
476 char *pdata,
477 unsigned int total_data_size,
478 unsigned int *ret_data_size,
479 connection_struct *conn,
480 struct ea_list *ea_list)
482 uint8_t *p = (uint8_t *)pdata;
483 uint8_t *last_start = NULL;
484 bool do_store_data = (pdata != NULL);
486 *ret_data_size = 0;
488 if (!lp_ea_support(SNUM(conn))) {
489 return NT_STATUS_NO_EAS_ON_FILE;
492 for (; ea_list; ea_list = ea_list->next) {
493 size_t dos_namelen;
494 fstring dos_ea_name;
495 size_t this_size;
496 size_t pad = 0;
498 if (last_start != NULL && do_store_data) {
499 SIVAL(last_start, 0, PTR_DIFF(p, last_start));
501 last_start = p;
503 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
504 dos_namelen = strlen(dos_ea_name);
505 if (dos_namelen > 255 || dos_namelen == 0) {
506 return NT_STATUS_INTERNAL_ERROR;
508 if (ea_list->ea.value.length > 65535) {
509 return NT_STATUS_INTERNAL_ERROR;
512 this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length;
514 if (ea_list->next) {
515 pad = (4 - (this_size % 4)) % 4;
516 this_size += pad;
519 if (do_store_data) {
520 if (this_size > total_data_size) {
521 return NT_STATUS_INFO_LENGTH_MISMATCH;
524 /* We know we have room. */
525 SIVAL(p, 0x00, 0); /* next offset */
526 SCVAL(p, 0x04, ea_list->ea.flags);
527 SCVAL(p, 0x05, dos_namelen);
528 SSVAL(p, 0x06, ea_list->ea.value.length);
529 strlcpy((char *)(p+0x08), dos_ea_name, dos_namelen+1);
530 memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
531 if (pad) {
532 memset(p + 0x08 + dos_namelen + 1 + ea_list->ea.value.length,
533 '\0',
534 pad);
536 total_data_size -= this_size;
539 p += this_size;
542 *ret_data_size = PTR_DIFF(p, pdata);
543 DEBUG(10,("fill_ea_chained_buffer: data_size = %u\n", *ret_data_size));
544 return NT_STATUS_OK;
547 static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const struct smb_filename *smb_fname)
549 size_t total_ea_len = 0;
550 TALLOC_CTX *mem_ctx;
551 struct ea_list *ea_list = NULL;
553 if (!lp_ea_support(SNUM(conn))) {
554 return 0;
556 mem_ctx = talloc_stackframe();
558 /* If this is a stream fsp, then we need to instead find the
559 * estimated ea len from the main file, not the stream
560 * (streams cannot have EAs), but the estimate isn't just 0 in
561 * this case! */
562 if (is_ntfs_stream_smb_fname(smb_fname)) {
563 fsp = NULL;
565 (void)get_ea_list_from_file_path(mem_ctx, conn, fsp, smb_fname->base_name, &total_ea_len, &ea_list);
566 if(conn->sconn->using_smb2) {
567 NTSTATUS status;
568 unsigned int ret_data_size;
570 * We're going to be using fill_ea_chained_buffer() to
571 * marshall EA's - this size is significantly larger
572 * than the SMB1 buffer. Re-calculate the size without
573 * marshalling.
575 status = fill_ea_chained_buffer(mem_ctx,
576 NULL,
578 &ret_data_size,
579 conn,
580 ea_list);
581 if (!NT_STATUS_IS_OK(status)) {
582 ret_data_size = 0;
584 total_ea_len = ret_data_size;
586 TALLOC_FREE(mem_ctx);
587 return total_ea_len;
590 /****************************************************************************
591 Ensure the EA name is case insensitive by matching any existing EA name.
592 ****************************************************************************/
594 static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, const char *fname, fstring unix_ea_name)
596 size_t total_ea_len;
597 TALLOC_CTX *mem_ctx = talloc_tos();
598 struct ea_list *ea_list;
599 NTSTATUS status = get_ea_list_from_file_path(mem_ctx, conn, fsp, fname, &total_ea_len, &ea_list);
600 if (!NT_STATUS_IS_OK(status)) {
601 return;
604 for (; ea_list; ea_list = ea_list->next) {
605 if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
606 DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
607 &unix_ea_name[5], ea_list->ea.name));
608 strlcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-5);
609 break;
614 /****************************************************************************
615 Set or delete an extended attribute.
616 ****************************************************************************/
618 NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
619 const struct smb_filename *smb_fname, struct ea_list *ea_list)
621 NTSTATUS status;
622 char *fname = NULL;
624 if (!lp_ea_support(SNUM(conn))) {
625 return NT_STATUS_EAS_NOT_SUPPORTED;
628 status = check_access(conn, fsp, smb_fname, FILE_WRITE_EA);
629 if (!NT_STATUS_IS_OK(status)) {
630 return status;
633 /* Setting EAs on streams isn't supported. */
634 if (is_ntfs_stream_smb_fname(smb_fname)) {
635 return NT_STATUS_INVALID_PARAMETER;
639 * Filter out invalid Windows EA names - before
640 * we set *any* of them.
643 if (ea_list_has_invalid_name(ea_list)) {
644 return STATUS_INVALID_EA_NAME;
647 fname = smb_fname->base_name;
649 for (;ea_list; ea_list = ea_list->next) {
650 int ret;
651 fstring unix_ea_name;
653 fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
654 fstrcat(unix_ea_name, ea_list->ea.name);
656 canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
658 DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
660 if (samba_private_attr_name(unix_ea_name)) {
661 DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
662 return NT_STATUS_ACCESS_DENIED;
665 if (ea_list->ea.value.length == 0) {
666 /* Remove the attribute. */
667 if (fsp && (fsp->fh->fd != -1)) {
668 DEBUG(10,("set_ea: deleting ea name %s on "
669 "file %s by file descriptor.\n",
670 unix_ea_name, fsp_str_dbg(fsp)));
671 ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name);
672 } else {
673 DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",
674 unix_ea_name, fname));
675 ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);
677 #ifdef ENOATTR
678 /* Removing a non existent attribute always succeeds. */
679 if (ret == -1 && errno == ENOATTR) {
680 DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",
681 unix_ea_name));
682 ret = 0;
684 #endif
685 } else {
686 if (fsp && (fsp->fh->fd != -1)) {
687 DEBUG(10,("set_ea: setting ea name %s on file "
688 "%s by file descriptor.\n",
689 unix_ea_name, fsp_str_dbg(fsp)));
690 ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name,
691 ea_list->ea.value.data, ea_list->ea.value.length, 0);
692 } else {
693 DEBUG(10,("set_ea: setting ea name %s on file %s.\n",
694 unix_ea_name, fname));
695 ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name,
696 ea_list->ea.value.data, ea_list->ea.value.length, 0);
700 if (ret == -1) {
701 #ifdef ENOTSUP
702 if (errno == ENOTSUP) {
703 return NT_STATUS_EAS_NOT_SUPPORTED;
705 #endif
706 return map_nt_error_from_unix(errno);
710 return NT_STATUS_OK;
712 /****************************************************************************
713 Read a list of EA names from an incoming data buffer. Create an ea_list with them.
714 ****************************************************************************/
716 static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
718 struct ea_list *ea_list_head = NULL;
719 size_t converted_size, offset = 0;
721 while (offset + 2 < data_size) {
722 struct ea_list *eal = talloc_zero(ctx, struct ea_list);
723 unsigned int namelen = CVAL(pdata,offset);
725 offset++; /* Go past the namelen byte. */
727 /* integer wrap paranioa. */
728 if ((offset + namelen < offset) || (offset + namelen < namelen) ||
729 (offset > data_size) || (namelen > data_size) ||
730 (offset + namelen >= data_size)) {
731 break;
733 /* Ensure the name is null terminated. */
734 if (pdata[offset + namelen] != '\0') {
735 return NULL;
737 if (!pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset],
738 &converted_size)) {
739 DEBUG(0,("read_ea_name_list: pull_ascii_talloc "
740 "failed: %s", strerror(errno)));
742 if (!eal->ea.name) {
743 return NULL;
746 offset += (namelen + 1); /* Go past the name + terminating zero. */
747 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
748 DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
751 return ea_list_head;
754 /****************************************************************************
755 Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
756 ****************************************************************************/
758 static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
760 struct ea_list *ea_list_head = NULL;
761 size_t offset = 0;
762 size_t bytes_used = 0;
764 while (offset < data_size) {
765 struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);
767 if (!eal) {
768 return NULL;
771 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
772 offset += bytes_used;
775 return ea_list_head;
778 /****************************************************************************
779 Count the total EA size needed.
780 ****************************************************************************/
782 static size_t ea_list_size(struct ea_list *ealist)
784 fstring dos_ea_name;
785 struct ea_list *listp;
786 size_t ret = 0;
788 for (listp = ealist; listp; listp = listp->next) {
789 push_ascii_fstring(dos_ea_name, listp->ea.name);
790 ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
792 /* Add on 4 for total length. */
793 if (ret) {
794 ret += 4;
797 return ret;
800 /****************************************************************************
801 Return a union of EA's from a file list and a list of names.
802 The TALLOC context for the two lists *MUST* be identical as we steal
803 memory from one list to add to another. JRA.
804 ****************************************************************************/
806 static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *file_list, size_t *total_ea_len)
808 struct ea_list *nlistp, *flistp;
810 for (nlistp = name_list; nlistp; nlistp = nlistp->next) {
811 for (flistp = file_list; flistp; flistp = flistp->next) {
812 if (strequal(nlistp->ea.name, flistp->ea.name)) {
813 break;
817 if (flistp) {
818 /* Copy the data from this entry. */
819 nlistp->ea.flags = flistp->ea.flags;
820 nlistp->ea.value = flistp->ea.value;
821 } else {
822 /* Null entry. */
823 nlistp->ea.flags = 0;
824 ZERO_STRUCT(nlistp->ea.value);
828 *total_ea_len = ea_list_size(name_list);
829 return name_list;
832 /****************************************************************************
833 Send the required number of replies back.
834 We assume all fields other than the data fields are
835 set correctly for the type of call.
836 HACK ! Always assumes smb_setup field is zero.
837 ****************************************************************************/
839 void send_trans2_replies(connection_struct *conn,
840 struct smb_request *req,
841 NTSTATUS status,
842 const char *params,
843 int paramsize,
844 const char *pdata,
845 int datasize,
846 int max_data_bytes)
848 /* As we are using a protocol > LANMAN1 then the max_send
849 variable must have been set in the sessetupX call.
850 This takes precedence over the max_xmit field in the
851 global struct. These different max_xmit variables should
852 be merged as this is now too confusing */
854 int data_to_send = datasize;
855 int params_to_send = paramsize;
856 int useable_space;
857 const char *pp = params;
858 const char *pd = pdata;
859 int params_sent_thistime, data_sent_thistime, total_sent_thistime;
860 int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
861 int data_alignment_offset = 0;
862 bool overflow = False;
863 struct smbXsrv_connection *xconn = req->xconn;
864 int max_send = xconn->smb1.sessions.max_send;
866 /* Modify the data_to_send and datasize and set the error if
867 we're trying to send more than max_data_bytes. We still send
868 the part of the packet(s) that fit. Strange, but needed
869 for OS/2. */
871 if (max_data_bytes > 0 && datasize > max_data_bytes) {
872 DEBUG(5,("send_trans2_replies: max_data_bytes %d exceeded by data %d\n",
873 max_data_bytes, datasize ));
874 datasize = data_to_send = max_data_bytes;
875 overflow = True;
878 /* If there genuinely are no parameters or data to send just send the empty packet */
880 if(params_to_send == 0 && data_to_send == 0) {
881 reply_outbuf(req, 10, 0);
882 if (NT_STATUS_V(status)) {
883 uint8_t eclass;
884 uint32_t ecode;
885 ntstatus_to_dos(status, &eclass, &ecode);
886 error_packet_set((char *)req->outbuf,
887 eclass, ecode, status,
888 __LINE__,__FILE__);
890 show_msg((char *)req->outbuf);
891 if (!srv_send_smb(xconn,
892 (char *)req->outbuf,
893 true, req->seqnum+1,
894 IS_CONN_ENCRYPTED(conn),
895 &req->pcd)) {
896 exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
898 TALLOC_FREE(req->outbuf);
899 return;
902 /* When sending params and data ensure that both are nicely aligned */
903 /* Only do this alignment when there is also data to send - else
904 can cause NT redirector problems. */
906 if (((params_to_send % 4) != 0) && (data_to_send != 0))
907 data_alignment_offset = 4 - (params_to_send % 4);
909 /* Space is bufsize minus Netbios over TCP header minus SMB header */
910 /* The alignment_offset is to align the param bytes on an even byte
911 boundary. NT 4.0 Beta needs this to work correctly. */
913 useable_space = max_send - (smb_size
914 + 2 * 10 /* wct */
915 + alignment_offset
916 + data_alignment_offset);
918 if (useable_space < 0) {
919 DEBUG(0, ("send_trans2_replies failed sanity useable_space "
920 "= %d!!!", useable_space));
921 exit_server_cleanly("send_trans2_replies: Not enough space");
924 while (params_to_send || data_to_send) {
925 /* Calculate whether we will totally or partially fill this packet */
927 total_sent_thistime = params_to_send + data_to_send;
929 /* We can never send more than useable_space */
931 * Note that 'useable_space' does not include the alignment offsets,
932 * but we must include the alignment offsets in the calculation of
933 * the length of the data we send over the wire, as the alignment offsets
934 * are sent here. Fix from Marc_Jacobsen@hp.com.
937 total_sent_thistime = MIN(total_sent_thistime, useable_space);
939 reply_outbuf(req, 10, total_sent_thistime + alignment_offset
940 + data_alignment_offset);
942 /* Set total params and data to be sent */
943 SSVAL(req->outbuf,smb_tprcnt,paramsize);
944 SSVAL(req->outbuf,smb_tdrcnt,datasize);
946 /* Calculate how many parameters and data we can fit into
947 * this packet. Parameters get precedence
950 params_sent_thistime = MIN(params_to_send,useable_space);
951 data_sent_thistime = useable_space - params_sent_thistime;
952 data_sent_thistime = MIN(data_sent_thistime,data_to_send);
954 SSVAL(req->outbuf,smb_prcnt, params_sent_thistime);
956 /* smb_proff is the offset from the start of the SMB header to the
957 parameter bytes, however the first 4 bytes of outbuf are
958 the Netbios over TCP header. Thus use smb_base() to subtract
959 them from the calculation */
961 SSVAL(req->outbuf,smb_proff,
962 ((smb_buf(req->outbuf)+alignment_offset)
963 - smb_base(req->outbuf)));
965 if(params_sent_thistime == 0)
966 SSVAL(req->outbuf,smb_prdisp,0);
967 else
968 /* Absolute displacement of param bytes sent in this packet */
969 SSVAL(req->outbuf,smb_prdisp,pp - params);
971 SSVAL(req->outbuf,smb_drcnt, data_sent_thistime);
972 if(data_sent_thistime == 0) {
973 SSVAL(req->outbuf,smb_droff,0);
974 SSVAL(req->outbuf,smb_drdisp, 0);
975 } else {
976 /* The offset of the data bytes is the offset of the
977 parameter bytes plus the number of parameters being sent this time */
978 SSVAL(req->outbuf, smb_droff,
979 ((smb_buf(req->outbuf)+alignment_offset)
980 - smb_base(req->outbuf))
981 + params_sent_thistime + data_alignment_offset);
982 SSVAL(req->outbuf,smb_drdisp, pd - pdata);
985 /* Initialize the padding for alignment */
987 if (alignment_offset != 0) {
988 memset(smb_buf(req->outbuf), 0, alignment_offset);
991 /* Copy the param bytes into the packet */
993 if(params_sent_thistime) {
994 memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
995 params_sent_thistime);
998 /* Copy in the data bytes */
999 if(data_sent_thistime) {
1000 if (data_alignment_offset != 0) {
1001 memset((smb_buf(req->outbuf)+alignment_offset+
1002 params_sent_thistime), 0,
1003 data_alignment_offset);
1005 memcpy(smb_buf(req->outbuf)+alignment_offset
1006 +params_sent_thistime+data_alignment_offset,
1007 pd,data_sent_thistime);
1010 DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
1011 params_sent_thistime, data_sent_thistime, useable_space));
1012 DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
1013 params_to_send, data_to_send, paramsize, datasize));
1015 if (overflow) {
1016 error_packet_set((char *)req->outbuf,
1017 ERRDOS,ERRbufferoverflow,
1018 STATUS_BUFFER_OVERFLOW,
1019 __LINE__,__FILE__);
1020 } else if (NT_STATUS_V(status)) {
1021 uint8_t eclass;
1022 uint32_t ecode;
1023 ntstatus_to_dos(status, &eclass, &ecode);
1024 error_packet_set((char *)req->outbuf,
1025 eclass, ecode, status,
1026 __LINE__,__FILE__);
1029 /* Send the packet */
1030 show_msg((char *)req->outbuf);
1031 if (!srv_send_smb(xconn,
1032 (char *)req->outbuf,
1033 true, req->seqnum+1,
1034 IS_CONN_ENCRYPTED(conn),
1035 &req->pcd))
1036 exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
1038 TALLOC_FREE(req->outbuf);
1040 pp += params_sent_thistime;
1041 pd += data_sent_thistime;
1043 params_to_send -= params_sent_thistime;
1044 data_to_send -= data_sent_thistime;
1046 /* Sanity check */
1047 if(params_to_send < 0 || data_to_send < 0) {
1048 DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
1049 params_to_send, data_to_send));
1050 return;
1054 return;
1057 /****************************************************************************
1058 Reply to a TRANSACT2_OPEN.
1059 ****************************************************************************/
1061 static void call_trans2open(connection_struct *conn,
1062 struct smb_request *req,
1063 char **pparams, int total_params,
1064 char **ppdata, int total_data,
1065 unsigned int max_data_bytes)
1067 struct smb_filename *smb_fname = NULL;
1068 char *params = *pparams;
1069 char *pdata = *ppdata;
1070 int deny_mode;
1071 int32 open_attr;
1072 bool oplock_request;
1073 #if 0
1074 bool return_additional_info;
1075 int16 open_sattr;
1076 time_t open_time;
1077 #endif
1078 int open_ofun;
1079 uint32 open_size;
1080 char *pname;
1081 char *fname = NULL;
1082 off_t size=0;
1083 int fattr=0,mtime=0;
1084 SMB_INO_T inode = 0;
1085 int smb_action = 0;
1086 files_struct *fsp;
1087 struct ea_list *ea_list = NULL;
1088 uint16 flags = 0;
1089 NTSTATUS status;
1090 uint32 access_mask;
1091 uint32 share_mode;
1092 uint32 create_disposition;
1093 uint32 create_options = 0;
1094 uint32_t private_flags = 0;
1095 TALLOC_CTX *ctx = talloc_tos();
1098 * Ensure we have enough parameters to perform the operation.
1101 if (total_params < 29) {
1102 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1103 goto out;
1106 flags = SVAL(params, 0);
1107 deny_mode = SVAL(params, 2);
1108 open_attr = SVAL(params,6);
1109 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
1110 if (oplock_request) {
1111 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
1114 #if 0
1115 return_additional_info = BITSETW(params,0);
1116 open_sattr = SVAL(params, 4);
1117 open_time = make_unix_date3(params+8);
1118 #endif
1119 open_ofun = SVAL(params,12);
1120 open_size = IVAL(params,14);
1121 pname = &params[28];
1123 if (IS_IPC(conn)) {
1124 reply_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1125 goto out;
1128 srvstr_get_path(ctx, params, req->flags2, &fname, pname,
1129 total_params - 28, STR_TERMINATE,
1130 &status);
1131 if (!NT_STATUS_IS_OK(status)) {
1132 reply_nterror(req, status);
1133 goto out;
1136 DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n",
1137 fname, (unsigned int)deny_mode, (unsigned int)open_attr,
1138 (unsigned int)open_ofun, open_size));
1140 status = filename_convert(ctx,
1141 conn,
1142 req->flags2 & FLAGS2_DFS_PATHNAMES,
1143 fname,
1145 NULL,
1146 &smb_fname);
1147 if (!NT_STATUS_IS_OK(status)) {
1148 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1149 reply_botherror(req,
1150 NT_STATUS_PATH_NOT_COVERED,
1151 ERRSRV, ERRbadpath);
1152 goto out;
1154 reply_nterror(req, status);
1155 goto out;
1158 if (open_ofun == 0) {
1159 reply_nterror(req, NT_STATUS_OBJECT_NAME_COLLISION);
1160 goto out;
1163 if (!map_open_params_to_ntcreate(smb_fname->base_name, deny_mode,
1164 open_ofun,
1165 &access_mask, &share_mode,
1166 &create_disposition,
1167 &create_options,
1168 &private_flags)) {
1169 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1170 goto out;
1173 /* Any data in this call is an EA list. */
1174 if (total_data && (total_data != 4)) {
1175 if (total_data < 10) {
1176 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1177 goto out;
1180 if (IVAL(pdata,0) > total_data) {
1181 DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n",
1182 IVAL(pdata,0), (unsigned int)total_data));
1183 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1184 goto out;
1187 ea_list = read_ea_list(talloc_tos(), pdata + 4,
1188 total_data - 4);
1189 if (!ea_list) {
1190 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1191 goto out;
1194 if (!lp_ea_support(SNUM(conn))) {
1195 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
1196 goto out;
1199 if (ea_list_has_invalid_name(ea_list)) {
1200 int param_len = 30;
1201 *pparams = (char *)SMB_REALLOC(*pparams, param_len);
1202 if(*pparams == NULL ) {
1203 reply_nterror(req, NT_STATUS_NO_MEMORY);
1204 goto out;
1206 params = *pparams;
1207 memset(params, '\0', param_len);
1208 send_trans2_replies(conn, req, STATUS_INVALID_EA_NAME,
1209 params, param_len, NULL, 0, max_data_bytes);
1210 goto out;
1214 status = SMB_VFS_CREATE_FILE(
1215 conn, /* conn */
1216 req, /* req */
1217 0, /* root_dir_fid */
1218 smb_fname, /* fname */
1219 access_mask, /* access_mask */
1220 share_mode, /* share_access */
1221 create_disposition, /* create_disposition*/
1222 create_options, /* create_options */
1223 open_attr, /* file_attributes */
1224 oplock_request, /* oplock_request */
1225 NULL, /* lease */
1226 open_size, /* allocation_size */
1227 private_flags,
1228 NULL, /* sd */
1229 ea_list, /* ea_list */
1230 &fsp, /* result */
1231 &smb_action, /* psbuf */
1232 NULL, NULL); /* create context */
1234 if (!NT_STATUS_IS_OK(status)) {
1235 if (open_was_deferred(req->xconn, req->mid)) {
1236 /* We have re-scheduled this call. */
1237 goto out;
1239 reply_openerror(req, status);
1240 goto out;
1243 size = get_file_size_stat(&smb_fname->st);
1244 fattr = dos_mode(conn, smb_fname);
1245 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1246 inode = smb_fname->st.st_ex_ino;
1247 if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
1248 close_file(req, fsp, ERROR_CLOSE);
1249 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1250 goto out;
1253 /* Realloc the size of parameters and data we will return */
1254 *pparams = (char *)SMB_REALLOC(*pparams, 30);
1255 if(*pparams == NULL ) {
1256 reply_nterror(req, NT_STATUS_NO_MEMORY);
1257 goto out;
1259 params = *pparams;
1261 SSVAL(params,0,fsp->fnum);
1262 SSVAL(params,2,fattr);
1263 srv_put_dos_date2(params,4, mtime);
1264 SIVAL(params,8, (uint32)size);
1265 SSVAL(params,12,deny_mode);
1266 SSVAL(params,14,0); /* open_type - file or directory. */
1267 SSVAL(params,16,0); /* open_state - only valid for IPC device. */
1269 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1270 smb_action |= EXTENDED_OPLOCK_GRANTED;
1273 SSVAL(params,18,smb_action);
1276 * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
1278 SIVAL(params,20,inode);
1279 SSVAL(params,24,0); /* Padding. */
1280 if (flags & 8) {
1281 uint32 ea_size = estimate_ea_size(conn, fsp,
1282 smb_fname);
1283 SIVAL(params, 26, ea_size);
1284 } else {
1285 SIVAL(params, 26, 0);
1288 /* Send the required number of replies */
1289 send_trans2_replies(conn, req, NT_STATUS_OK, params, 30, *ppdata, 0, max_data_bytes);
1290 out:
1291 TALLOC_FREE(smb_fname);
1294 /*********************************************************
1295 Routine to check if a given string matches exactly.
1296 as a special case a mask of "." does NOT match. That
1297 is required for correct wildcard semantics
1298 Case can be significant or not.
1299 **********************************************************/
1301 static bool exact_match(bool has_wild,
1302 bool case_sensitive,
1303 const char *str,
1304 const char *mask)
1306 if (mask[0] == '.' && mask[1] == 0) {
1307 return false;
1310 if (has_wild) {
1311 return false;
1314 if (case_sensitive) {
1315 return strcmp(str,mask)==0;
1316 } else {
1317 return strcasecmp_m(str,mask) == 0;
1321 /****************************************************************************
1322 Return the filetype for UNIX extensions.
1323 ****************************************************************************/
1325 static uint32 unix_filetype(mode_t mode)
1327 if(S_ISREG(mode))
1328 return UNIX_TYPE_FILE;
1329 else if(S_ISDIR(mode))
1330 return UNIX_TYPE_DIR;
1331 #ifdef S_ISLNK
1332 else if(S_ISLNK(mode))
1333 return UNIX_TYPE_SYMLINK;
1334 #endif
1335 #ifdef S_ISCHR
1336 else if(S_ISCHR(mode))
1337 return UNIX_TYPE_CHARDEV;
1338 #endif
1339 #ifdef S_ISBLK
1340 else if(S_ISBLK(mode))
1341 return UNIX_TYPE_BLKDEV;
1342 #endif
1343 #ifdef S_ISFIFO
1344 else if(S_ISFIFO(mode))
1345 return UNIX_TYPE_FIFO;
1346 #endif
1347 #ifdef S_ISSOCK
1348 else if(S_ISSOCK(mode))
1349 return UNIX_TYPE_SOCKET;
1350 #endif
1352 DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode));
1353 return UNIX_TYPE_UNKNOWN;
1356 /****************************************************************************
1357 Map wire perms onto standard UNIX permissions. Obey share restrictions.
1358 ****************************************************************************/
1360 enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_DIR};
1362 static NTSTATUS unix_perms_from_wire( connection_struct *conn,
1363 const SMB_STRUCT_STAT *psbuf,
1364 uint32 perms,
1365 enum perm_type ptype,
1366 mode_t *ret_perms)
1368 mode_t ret = 0;
1370 if (perms == SMB_MODE_NO_CHANGE) {
1371 if (!VALID_STAT(*psbuf)) {
1372 return NT_STATUS_INVALID_PARAMETER;
1373 } else {
1374 *ret_perms = psbuf->st_ex_mode;
1375 return NT_STATUS_OK;
1379 ret |= ((perms & UNIX_X_OTH ) ? S_IXOTH : 0);
1380 ret |= ((perms & UNIX_W_OTH ) ? S_IWOTH : 0);
1381 ret |= ((perms & UNIX_R_OTH ) ? S_IROTH : 0);
1382 ret |= ((perms & UNIX_X_GRP ) ? S_IXGRP : 0);
1383 ret |= ((perms & UNIX_W_GRP ) ? S_IWGRP : 0);
1384 ret |= ((perms & UNIX_R_GRP ) ? S_IRGRP : 0);
1385 ret |= ((perms & UNIX_X_USR ) ? S_IXUSR : 0);
1386 ret |= ((perms & UNIX_W_USR ) ? S_IWUSR : 0);
1387 ret |= ((perms & UNIX_R_USR ) ? S_IRUSR : 0);
1388 #ifdef S_ISVTX
1389 ret |= ((perms & UNIX_STICKY ) ? S_ISVTX : 0);
1390 #endif
1391 #ifdef S_ISGID
1392 ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0);
1393 #endif
1394 #ifdef S_ISUID
1395 ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0);
1396 #endif
1398 if (ptype == PERM_NEW_FILE) {
1400 * "create mask"/"force create mode" are
1401 * only applied to new files, not existing ones.
1403 ret &= lp_create_mask(SNUM(conn));
1404 /* Add in force bits */
1405 ret |= lp_force_create_mode(SNUM(conn));
1406 } else if (ptype == PERM_NEW_DIR) {
1408 * "directory mask"/"force directory mode" are
1409 * only applied to new directories, not existing ones.
1411 ret &= lp_directory_mask(SNUM(conn));
1412 /* Add in force bits */
1413 ret |= lp_force_directory_mode(SNUM(conn));
1416 *ret_perms = ret;
1417 return NT_STATUS_OK;
1420 /****************************************************************************
1421 Needed to show the msdfs symlinks as directories. Modifies psbuf
1422 to be a directory if it's a msdfs link.
1423 ****************************************************************************/
1425 static bool check_msdfs_link(connection_struct *conn,
1426 const char *pathname,
1427 SMB_STRUCT_STAT *psbuf)
1429 int saved_errno = errno;
1430 if(lp_host_msdfs() &&
1431 lp_msdfs_root(SNUM(conn)) &&
1432 is_msdfs_link(conn, pathname, psbuf)) {
1434 DEBUG(5,("check_msdfs_link: Masquerading msdfs link %s "
1435 "as a directory\n",
1436 pathname));
1437 psbuf->st_ex_mode = (psbuf->st_ex_mode & 0xFFF) | S_IFDIR;
1438 errno = saved_errno;
1439 return true;
1441 errno = saved_errno;
1442 return false;
1446 /****************************************************************************
1447 Get a level dependent lanman2 dir entry.
1448 ****************************************************************************/
1450 struct smbd_dirptr_lanman2_state {
1451 connection_struct *conn;
1452 uint32_t info_level;
1453 bool check_mangled_names;
1454 bool has_wild;
1455 bool got_exact_match;
1458 static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx,
1459 void *private_data,
1460 const char *dname,
1461 const char *mask,
1462 char **_fname)
1464 struct smbd_dirptr_lanman2_state *state =
1465 (struct smbd_dirptr_lanman2_state *)private_data;
1466 bool ok;
1467 char mangled_name[13]; /* mangled 8.3 name. */
1468 bool got_match;
1469 const char *fname;
1471 /* Mangle fname if it's an illegal name. */
1472 if (mangle_must_mangle(dname, state->conn->params)) {
1474 * Slow path - ensure we can push the original name as UCS2. If
1475 * not, then just don't return this name.
1477 NTSTATUS status;
1478 size_t ret_len = 0;
1479 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1480 uint8_t *tmp = talloc_array(talloc_tos(),
1481 uint8,
1482 len);
1484 status = srvstr_push(NULL,
1485 FLAGS2_UNICODE_STRINGS,
1486 tmp,
1487 dname,
1488 len,
1489 STR_TERMINATE,
1490 &ret_len);
1492 TALLOC_FREE(tmp);
1494 if (!NT_STATUS_IS_OK(status)) {
1495 return false;
1498 ok = name_to_8_3(dname, mangled_name,
1499 true, state->conn->params);
1500 if (!ok) {
1501 return false;
1503 fname = mangled_name;
1504 } else {
1505 fname = dname;
1508 got_match = exact_match(state->has_wild,
1509 state->conn->case_sensitive,
1510 fname, mask);
1511 state->got_exact_match = got_match;
1512 if (!got_match) {
1513 got_match = mask_match(fname, mask,
1514 state->conn->case_sensitive);
1517 if(!got_match && state->check_mangled_names &&
1518 !mangle_is_8_3(fname, false, state->conn->params)) {
1520 * It turns out that NT matches wildcards against
1521 * both long *and* short names. This may explain some
1522 * of the wildcard wierdness from old DOS clients
1523 * that some people have been seeing.... JRA.
1525 /* Force the mangling into 8.3. */
1526 ok = name_to_8_3(fname, mangled_name,
1527 false, state->conn->params);
1528 if (!ok) {
1529 return false;
1532 got_match = exact_match(state->has_wild,
1533 state->conn->case_sensitive,
1534 mangled_name, mask);
1535 state->got_exact_match = got_match;
1536 if (!got_match) {
1537 got_match = mask_match(mangled_name, mask,
1538 state->conn->case_sensitive);
1542 if (!got_match) {
1543 return false;
1546 *_fname = talloc_strdup(ctx, fname);
1547 if (*_fname == NULL) {
1548 return false;
1551 return true;
1554 static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
1555 void *private_data,
1556 struct smb_filename *smb_fname,
1557 uint32_t *_mode)
1559 struct smbd_dirptr_lanman2_state *state =
1560 (struct smbd_dirptr_lanman2_state *)private_data;
1561 bool ms_dfs_link = false;
1562 uint32_t mode = 0;
1564 if (INFO_LEVEL_IS_UNIX(state->info_level)) {
1565 if (SMB_VFS_LSTAT(state->conn, smb_fname) != 0) {
1566 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1567 "Couldn't lstat [%s] (%s)\n",
1568 smb_fname_str_dbg(smb_fname),
1569 strerror(errno)));
1570 return false;
1572 } else if (!VALID_STAT(smb_fname->st) &&
1573 SMB_VFS_STAT(state->conn, smb_fname) != 0) {
1574 /* Needed to show the msdfs symlinks as
1575 * directories */
1577 ms_dfs_link = check_msdfs_link(state->conn,
1578 smb_fname->base_name,
1579 &smb_fname->st);
1580 if (!ms_dfs_link) {
1581 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1582 "Couldn't stat [%s] (%s)\n",
1583 smb_fname_str_dbg(smb_fname),
1584 strerror(errno)));
1585 return false;
1589 if (ms_dfs_link) {
1590 mode = dos_mode_msdfs(state->conn, smb_fname);
1591 } else {
1592 mode = dos_mode(state->conn, smb_fname);
1595 *_mode = mode;
1596 return true;
1599 static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
1600 connection_struct *conn,
1601 uint16_t flags2,
1602 uint32_t info_level,
1603 struct ea_list *name_list,
1604 bool check_mangled_names,
1605 bool requires_resume_key,
1606 uint32_t mode,
1607 const char *fname,
1608 const struct smb_filename *smb_fname,
1609 int space_remaining,
1610 uint8_t align,
1611 bool do_pad,
1612 char *base_data,
1613 char **ppdata,
1614 char *end_data,
1615 uint64_t *last_entry_off)
1617 char *p, *q, *pdata = *ppdata;
1618 uint32_t reskey=0;
1619 uint64_t file_size = 0;
1620 uint64_t allocation_size = 0;
1621 uint64_t file_index = 0;
1622 size_t len = 0;
1623 struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts;
1624 time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
1625 char *nameptr;
1626 char *last_entry_ptr;
1627 bool was_8_3;
1628 int off;
1629 int pad = 0;
1630 NTSTATUS status;
1631 struct readdir_attr_data *readdir_attr_data = NULL;
1633 ZERO_STRUCT(mdate_ts);
1634 ZERO_STRUCT(adate_ts);
1635 ZERO_STRUCT(create_date_ts);
1636 ZERO_STRUCT(cdate_ts);
1638 if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) {
1639 file_size = get_file_size_stat(&smb_fname->st);
1641 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
1643 status = SMB_VFS_READDIR_ATTR(conn, smb_fname, ctx, &readdir_attr_data);
1644 if (!NT_STATUS_IS_OK(status)) {
1645 if (!NT_STATUS_EQUAL(NT_STATUS_NOT_SUPPORTED, status)) {
1646 return status;
1650 file_index = get_FileIndex(conn, &smb_fname->st);
1652 mdate_ts = smb_fname->st.st_ex_mtime;
1653 adate_ts = smb_fname->st.st_ex_atime;
1654 create_date_ts = get_create_timespec(conn, NULL, smb_fname);
1655 cdate_ts = get_change_timespec(conn, NULL, smb_fname);
1657 if (lp_dos_filetime_resolution(SNUM(conn))) {
1658 dos_filetime_timespec(&create_date_ts);
1659 dos_filetime_timespec(&mdate_ts);
1660 dos_filetime_timespec(&adate_ts);
1661 dos_filetime_timespec(&cdate_ts);
1664 create_date = convert_timespec_to_time_t(create_date_ts);
1665 mdate = convert_timespec_to_time_t(mdate_ts);
1666 adate = convert_timespec_to_time_t(adate_ts);
1668 /* align the record */
1669 SMB_ASSERT(align >= 1);
1671 off = (int)PTR_DIFF(pdata, base_data);
1672 pad = (off + (align-1)) & ~(align-1);
1673 pad -= off;
1675 if (pad && pad > space_remaining) {
1676 DEBUG(9,("smbd_marshall_dir_entry: out of space "
1677 "for padding (wanted %u, had %d)\n",
1678 (unsigned int)pad,
1679 space_remaining ));
1680 return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
1683 off += pad;
1684 /* initialize padding to 0 */
1685 if (pad) {
1686 memset(pdata, 0, pad);
1688 space_remaining -= pad;
1690 DEBUG(10,("smbd_marshall_dir_entry: space_remaining = %d\n",
1691 space_remaining ));
1693 pdata += pad;
1694 p = pdata;
1695 last_entry_ptr = p;
1697 pad = 0;
1698 off = 0;
1700 switch (info_level) {
1701 case SMB_FIND_INFO_STANDARD:
1702 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_INFO_STANDARD\n"));
1703 if(requires_resume_key) {
1704 SIVAL(p,0,reskey);
1705 p += 4;
1707 srv_put_dos_date2(p,0,create_date);
1708 srv_put_dos_date2(p,4,adate);
1709 srv_put_dos_date2(p,8,mdate);
1710 SIVAL(p,12,(uint32)file_size);
1711 SIVAL(p,16,(uint32)allocation_size);
1712 SSVAL(p,20,mode);
1713 p += 23;
1714 nameptr = p;
1715 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1716 p += ucs2_align(base_data, p, 0);
1718 status = srvstr_push(base_data, flags2, p,
1719 fname, PTR_DIFF(end_data, p),
1720 STR_TERMINATE, &len);
1721 if (!NT_STATUS_IS_OK(status)) {
1722 return status;
1724 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1725 if (len > 2) {
1726 SCVAL(nameptr, -1, len - 2);
1727 } else {
1728 SCVAL(nameptr, -1, 0);
1730 } else {
1731 if (len > 1) {
1732 SCVAL(nameptr, -1, len - 1);
1733 } else {
1734 SCVAL(nameptr, -1, 0);
1737 p += len;
1738 break;
1740 case SMB_FIND_EA_SIZE:
1741 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_SIZE\n"));
1742 if (requires_resume_key) {
1743 SIVAL(p,0,reskey);
1744 p += 4;
1746 srv_put_dos_date2(p,0,create_date);
1747 srv_put_dos_date2(p,4,adate);
1748 srv_put_dos_date2(p,8,mdate);
1749 SIVAL(p,12,(uint32)file_size);
1750 SIVAL(p,16,(uint32)allocation_size);
1751 SSVAL(p,20,mode);
1753 unsigned int ea_size = estimate_ea_size(conn, NULL,
1754 smb_fname);
1755 SIVAL(p,22,ea_size); /* Extended attributes */
1757 p += 27;
1758 nameptr = p - 1;
1759 status = srvstr_push(base_data, flags2,
1760 p, fname, PTR_DIFF(end_data, p),
1761 STR_TERMINATE | STR_NOALIGN, &len);
1762 if (!NT_STATUS_IS_OK(status)) {
1763 return status;
1765 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1766 if (len > 2) {
1767 len -= 2;
1768 } else {
1769 len = 0;
1771 } else {
1772 if (len > 1) {
1773 len -= 1;
1774 } else {
1775 len = 0;
1778 SCVAL(nameptr,0,len);
1779 p += len;
1780 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1781 break;
1783 case SMB_FIND_EA_LIST:
1785 struct ea_list *file_list = NULL;
1786 size_t ea_len = 0;
1788 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_LIST\n"));
1789 if (!name_list) {
1790 return NT_STATUS_INVALID_PARAMETER;
1792 if (requires_resume_key) {
1793 SIVAL(p,0,reskey);
1794 p += 4;
1796 srv_put_dos_date2(p,0,create_date);
1797 srv_put_dos_date2(p,4,adate);
1798 srv_put_dos_date2(p,8,mdate);
1799 SIVAL(p,12,(uint32)file_size);
1800 SIVAL(p,16,(uint32)allocation_size);
1801 SSVAL(p,20,mode);
1802 p += 22; /* p now points to the EA area. */
1804 status = get_ea_list_from_file(ctx, conn, NULL,
1805 smb_fname,
1806 &ea_len, &file_list);
1807 if (!NT_STATUS_IS_OK(status)) {
1808 file_list = NULL;
1810 name_list = ea_list_union(name_list, file_list, &ea_len);
1812 /* We need to determine if this entry will fit in the space available. */
1813 /* Max string size is 255 bytes. */
1814 if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
1815 DEBUG(9,("smbd_marshall_dir_entry: out of space "
1816 "(wanted %u, had %d)\n",
1817 (unsigned int)PTR_DIFF(p + 255 + ea_len,pdata),
1818 space_remaining ));
1819 return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
1822 /* Push the ea_data followed by the name. */
1823 p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
1824 nameptr = p;
1825 status = srvstr_push(base_data, flags2,
1826 p + 1, fname, PTR_DIFF(end_data, p+1),
1827 STR_TERMINATE | STR_NOALIGN, &len);
1828 if (!NT_STATUS_IS_OK(status)) {
1829 return status;
1831 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1832 if (len > 2) {
1833 len -= 2;
1834 } else {
1835 len = 0;
1837 } else {
1838 if (len > 1) {
1839 len -= 1;
1840 } else {
1841 len = 0;
1844 SCVAL(nameptr,0,len);
1845 p += len + 1;
1846 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1847 break;
1850 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
1851 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
1852 was_8_3 = mangle_is_8_3(fname, True, conn->params);
1853 p += 4;
1854 SIVAL(p,0,reskey); p += 4;
1855 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1856 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1857 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1858 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1859 SOFF_T(p,0,file_size); p += 8;
1860 SOFF_T(p,0,allocation_size); p += 8;
1861 SIVAL(p,0,mode); p += 4;
1862 q = p; p += 4; /* q is placeholder for name length. */
1863 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1864 SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1865 } else {
1866 unsigned int ea_size = estimate_ea_size(conn, NULL,
1867 smb_fname);
1868 SIVAL(p,0,ea_size); /* Extended attributes */
1870 p += 4;
1871 /* Clear the short name buffer. This is
1872 * IMPORTANT as not doing so will trigger
1873 * a Win2k client bug. JRA.
1875 if (!was_8_3 && check_mangled_names) {
1876 char mangled_name[13]; /* mangled 8.3 name. */
1877 if (!name_to_8_3(fname,mangled_name,True,
1878 conn->params)) {
1879 /* Error - mangle failed ! */
1880 memset(mangled_name,'\0',12);
1882 mangled_name[12] = 0;
1883 status = srvstr_push(base_data, flags2,
1884 p+2, mangled_name, 24,
1885 STR_UPPER|STR_UNICODE, &len);
1886 if (!NT_STATUS_IS_OK(status)) {
1887 return status;
1889 if (len < 24) {
1890 memset(p + 2 + len,'\0',24 - len);
1892 SSVAL(p, 0, len);
1893 } else {
1894 memset(p,'\0',26);
1896 p += 2 + 24;
1897 status = srvstr_push(base_data, flags2, p,
1898 fname, PTR_DIFF(end_data, p),
1899 STR_TERMINATE_ASCII, &len);
1900 if (!NT_STATUS_IS_OK(status)) {
1901 return status;
1903 SIVAL(q,0,len);
1904 p += len;
1906 len = PTR_DIFF(p, pdata);
1907 pad = (len + (align-1)) & ~(align-1);
1909 * offset to the next entry, the caller
1910 * will overwrite it for the last entry
1911 * that's why we always include the padding
1913 SIVAL(pdata,0,pad);
1915 * set padding to zero
1917 if (do_pad) {
1918 memset(p, 0, pad - len);
1919 p = pdata + pad;
1920 } else {
1921 p = pdata + len;
1923 break;
1925 case SMB_FIND_FILE_DIRECTORY_INFO:
1926 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
1927 p += 4;
1928 SIVAL(p,0,reskey); p += 4;
1929 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1930 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1931 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1932 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1933 SOFF_T(p,0,file_size); p += 8;
1934 SOFF_T(p,0,allocation_size); p += 8;
1935 SIVAL(p,0,mode); p += 4;
1936 status = srvstr_push(base_data, flags2,
1937 p + 4, fname, PTR_DIFF(end_data, p+4),
1938 STR_TERMINATE_ASCII, &len);
1939 if (!NT_STATUS_IS_OK(status)) {
1940 return status;
1942 SIVAL(p,0,len);
1943 p += 4 + len;
1945 len = PTR_DIFF(p, pdata);
1946 pad = (len + (align-1)) & ~(align-1);
1948 * offset to the next entry, the caller
1949 * will overwrite it for the last entry
1950 * that's why we always include the padding
1952 SIVAL(pdata,0,pad);
1954 * set padding to zero
1956 if (do_pad) {
1957 memset(p, 0, pad - len);
1958 p = pdata + pad;
1959 } else {
1960 p = pdata + len;
1962 break;
1964 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
1965 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
1966 p += 4;
1967 SIVAL(p,0,reskey); p += 4;
1968 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1969 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1970 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1971 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1972 SOFF_T(p,0,file_size); p += 8;
1973 SOFF_T(p,0,allocation_size); p += 8;
1974 SIVAL(p,0,mode); p += 4;
1975 q = p; p += 4; /* q is placeholder for name length. */
1977 unsigned int ea_size = estimate_ea_size(conn, NULL,
1978 smb_fname);
1979 SIVAL(p,0,ea_size); /* Extended attributes */
1980 p +=4;
1982 status = srvstr_push(base_data, flags2, p,
1983 fname, PTR_DIFF(end_data, p),
1984 STR_TERMINATE_ASCII, &len);
1985 if (!NT_STATUS_IS_OK(status)) {
1986 return status;
1988 SIVAL(q, 0, len);
1989 p += len;
1991 len = PTR_DIFF(p, pdata);
1992 pad = (len + (align-1)) & ~(align-1);
1994 * offset to the next entry, the caller
1995 * will overwrite it for the last entry
1996 * that's why we always include the padding
1998 SIVAL(pdata,0,pad);
2000 * set padding to zero
2002 if (do_pad) {
2003 memset(p, 0, pad - len);
2004 p = pdata + pad;
2005 } else {
2006 p = pdata + len;
2008 break;
2010 case SMB_FIND_FILE_NAMES_INFO:
2011 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
2012 p += 4;
2013 SIVAL(p,0,reskey); p += 4;
2014 p += 4;
2015 /* this must *not* be null terminated or w2k gets in a loop trying to set an
2016 acl on a dir (tridge) */
2017 status = srvstr_push(base_data, flags2, p,
2018 fname, PTR_DIFF(end_data, p),
2019 STR_TERMINATE_ASCII, &len);
2020 if (!NT_STATUS_IS_OK(status)) {
2021 return status;
2023 SIVAL(p, -4, len);
2024 p += len;
2026 len = PTR_DIFF(p, pdata);
2027 pad = (len + (align-1)) & ~(align-1);
2029 * offset to the next entry, the caller
2030 * will overwrite it for the last entry
2031 * that's why we always include the padding
2033 SIVAL(pdata,0,pad);
2035 * set padding to zero
2037 if (do_pad) {
2038 memset(p, 0, pad - len);
2039 p = pdata + pad;
2040 } else {
2041 p = pdata + len;
2043 break;
2045 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
2046 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
2047 p += 4;
2048 SIVAL(p,0,reskey); p += 4;
2049 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
2050 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
2051 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
2052 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
2053 SOFF_T(p,0,file_size); p += 8;
2054 SOFF_T(p,0,allocation_size); p += 8;
2055 SIVAL(p,0,mode); p += 4;
2056 q = p; p += 4; /* q is placeholder for name length. */
2057 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
2058 SIVAL(p, 0, IO_REPARSE_TAG_DFS);
2059 } else {
2060 unsigned int ea_size = estimate_ea_size(conn, NULL,
2061 smb_fname);
2062 SIVAL(p,0,ea_size); /* Extended attributes */
2064 p += 4;
2065 SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
2066 SBVAL(p,0,file_index); p += 8;
2067 status = srvstr_push(base_data, flags2, p,
2068 fname, PTR_DIFF(end_data, p),
2069 STR_TERMINATE_ASCII, &len);
2070 if (!NT_STATUS_IS_OK(status)) {
2071 return status;
2073 SIVAL(q, 0, len);
2074 p += len;
2076 len = PTR_DIFF(p, pdata);
2077 pad = (len + (align-1)) & ~(align-1);
2079 * offset to the next entry, the caller
2080 * will overwrite it for the last entry
2081 * that's why we always include the padding
2083 SIVAL(pdata,0,pad);
2085 * set padding to zero
2087 if (do_pad) {
2088 memset(p, 0, pad - len);
2089 p = pdata + pad;
2090 } else {
2091 p = pdata + len;
2093 break;
2095 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
2096 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
2097 was_8_3 = mangle_is_8_3(fname, True, conn->params);
2098 p += 4;
2099 SIVAL(p,0,reskey); p += 4;
2100 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
2101 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
2102 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
2103 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
2104 SOFF_T(p,0,file_size); p += 8;
2105 SOFF_T(p,0,allocation_size); p += 8;
2106 SIVAL(p,0,mode); p += 4;
2107 q = p; p += 4; /* q is placeholder for name length */
2108 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
2109 SIVAL(p, 0, IO_REPARSE_TAG_DFS);
2110 } else if (readdir_attr_data &&
2111 readdir_attr_data->type == RDATTR_AAPL) {
2113 * OS X specific SMB2 extension negotiated via
2114 * AAPL create context: return max_access in
2115 * ea_size field.
2117 SIVAL(p, 0, readdir_attr_data->attr_data.aapl.max_access);
2118 } else {
2119 unsigned int ea_size = estimate_ea_size(conn, NULL,
2120 smb_fname);
2121 SIVAL(p,0,ea_size); /* Extended attributes */
2123 p += 4;
2125 if (readdir_attr_data &&
2126 readdir_attr_data->type == RDATTR_AAPL) {
2128 * OS X specific SMB2 extension negotiated via
2129 * AAPL create context: return resource fork
2130 * length and compressed FinderInfo in
2131 * shortname field.
2133 * According to documentation short_name_len
2134 * should be 0, but on the wire behaviour
2135 * shows its set to 24 by clients.
2137 SSVAL(p, 0, 24);
2139 /* Resourefork length */
2140 SBVAL(p, 2, readdir_attr_data->attr_data.aapl.rfork_size);
2142 /* Compressed FinderInfo */
2143 memcpy(p + 10, &readdir_attr_data->attr_data.aapl.finder_info, 16);
2144 } else if (!was_8_3 && check_mangled_names) {
2145 char mangled_name[13]; /* mangled 8.3 name. */
2146 if (!name_to_8_3(fname,mangled_name,True,
2147 conn->params)) {
2148 /* Error - mangle failed ! */
2149 memset(mangled_name,'\0',12);
2151 mangled_name[12] = 0;
2152 status = srvstr_push(base_data, flags2,
2153 p+2, mangled_name, 24,
2154 STR_UPPER|STR_UNICODE, &len);
2155 if (!NT_STATUS_IS_OK(status)) {
2156 return status;
2158 SSVAL(p, 0, len);
2159 if (len < 24) {
2160 memset(p + 2 + len,'\0',24 - len);
2162 SSVAL(p, 0, len);
2163 } else {
2164 /* Clear the short name buffer. This is
2165 * IMPORTANT as not doing so will trigger
2166 * a Win2k client bug. JRA.
2168 memset(p,'\0',26);
2170 p += 26;
2172 /* Reserved ? */
2173 if (readdir_attr_data &&
2174 readdir_attr_data->type == RDATTR_AAPL) {
2176 * OS X specific SMB2 extension negotiated via
2177 * AAPL create context: return UNIX mode in
2178 * reserved field.
2180 uint16_t aapl_mode = (uint16_t)readdir_attr_data->attr_data.aapl.unix_mode;
2181 SSVAL(p, 0, aapl_mode);
2182 } else {
2183 SSVAL(p, 0, 0);
2185 p += 2;
2187 SBVAL(p,0,file_index); p += 8;
2188 status = srvstr_push(base_data, flags2, p,
2189 fname, PTR_DIFF(end_data, p),
2190 STR_TERMINATE_ASCII, &len);
2191 if (!NT_STATUS_IS_OK(status)) {
2192 return status;
2194 SIVAL(q,0,len);
2195 p += len;
2197 len = PTR_DIFF(p, pdata);
2198 pad = (len + (align-1)) & ~(align-1);
2200 * offset to the next entry, the caller
2201 * will overwrite it for the last entry
2202 * that's why we always include the padding
2204 SIVAL(pdata,0,pad);
2206 * set padding to zero
2208 if (do_pad) {
2209 memset(p, 0, pad - len);
2210 p = pdata + pad;
2211 } else {
2212 p = pdata + len;
2214 break;
2216 /* CIFS UNIX Extension. */
2218 case SMB_FIND_FILE_UNIX:
2219 case SMB_FIND_FILE_UNIX_INFO2:
2220 p+= 4;
2221 SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
2223 /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
2225 if (info_level == SMB_FIND_FILE_UNIX) {
2226 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX\n"));
2227 p = store_file_unix_basic(conn, p,
2228 NULL, &smb_fname->st);
2229 status = srvstr_push(base_data, flags2, p,
2230 fname, PTR_DIFF(end_data, p),
2231 STR_TERMINATE, &len);
2232 if (!NT_STATUS_IS_OK(status)) {
2233 return status;
2235 } else {
2236 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
2237 p = store_file_unix_basic_info2(conn, p,
2238 NULL, &smb_fname->st);
2239 nameptr = p;
2240 p += 4;
2241 status = srvstr_push(base_data, flags2, p, fname,
2242 PTR_DIFF(end_data, p), 0, &len);
2243 if (!NT_STATUS_IS_OK(status)) {
2244 return status;
2246 SIVAL(nameptr, 0, len);
2249 p += len;
2251 len = PTR_DIFF(p, pdata);
2252 pad = (len + (align-1)) & ~(align-1);
2254 * offset to the next entry, the caller
2255 * will overwrite it for the last entry
2256 * that's why we always include the padding
2258 SIVAL(pdata,0,pad);
2260 * set padding to zero
2262 if (do_pad) {
2263 memset(p, 0, pad - len);
2264 p = pdata + pad;
2265 } else {
2266 p = pdata + len;
2268 /* End of SMB_QUERY_FILE_UNIX_BASIC */
2270 break;
2272 default:
2273 return NT_STATUS_INVALID_LEVEL;
2276 if (PTR_DIFF(p,pdata) > space_remaining) {
2277 DEBUG(9,("smbd_marshall_dir_entry: out of space "
2278 "(wanted %u, had %d)\n",
2279 (unsigned int)PTR_DIFF(p,pdata),
2280 space_remaining ));
2281 return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
2284 /* Setup the last entry pointer, as an offset from base_data */
2285 *last_entry_off = PTR_DIFF(last_entry_ptr,base_data);
2286 /* Advance the data pointer to the next slot */
2287 *ppdata = p;
2289 return NT_STATUS_OK;
2292 NTSTATUS smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
2293 connection_struct *conn,
2294 struct dptr_struct *dirptr,
2295 uint16 flags2,
2296 const char *path_mask,
2297 uint32 dirtype,
2298 int info_level,
2299 int requires_resume_key,
2300 bool dont_descend,
2301 bool ask_sharemode,
2302 uint8_t align,
2303 bool do_pad,
2304 char **ppdata,
2305 char *base_data,
2306 char *end_data,
2307 int space_remaining,
2308 bool *got_exact_match,
2309 int *_last_entry_off,
2310 struct ea_list *name_list)
2312 const char *p;
2313 const char *mask = NULL;
2314 long prev_dirpos = 0;
2315 uint32_t mode = 0;
2316 char *fname = NULL;
2317 struct smb_filename *smb_fname = NULL;
2318 struct smbd_dirptr_lanman2_state state;
2319 bool ok;
2320 uint64_t last_entry_off = 0;
2321 NTSTATUS status;
2323 ZERO_STRUCT(state);
2324 state.conn = conn;
2325 state.info_level = info_level;
2326 state.check_mangled_names = lp_mangled_names(conn->params);
2327 state.has_wild = dptr_has_wild(dirptr);
2328 state.got_exact_match = false;
2330 *got_exact_match = false;
2332 p = strrchr_m(path_mask,'/');
2333 if(p != NULL) {
2334 if(p[1] == '\0') {
2335 mask = "*.*";
2336 } else {
2337 mask = p+1;
2339 } else {
2340 mask = path_mask;
2343 ok = smbd_dirptr_get_entry(ctx,
2344 dirptr,
2345 mask,
2346 dirtype,
2347 dont_descend,
2348 ask_sharemode,
2349 smbd_dirptr_lanman2_match_fn,
2350 smbd_dirptr_lanman2_mode_fn,
2351 &state,
2352 &fname,
2353 &smb_fname,
2354 &mode,
2355 &prev_dirpos);
2356 if (!ok) {
2357 return NT_STATUS_END_OF_FILE;
2360 *got_exact_match = state.got_exact_match;
2362 status = smbd_marshall_dir_entry(ctx,
2363 conn,
2364 flags2,
2365 info_level,
2366 name_list,
2367 state.check_mangled_names,
2368 requires_resume_key,
2369 mode,
2370 fname,
2371 smb_fname,
2372 space_remaining,
2373 align,
2374 do_pad,
2375 base_data,
2376 ppdata,
2377 end_data,
2378 &last_entry_off);
2379 TALLOC_FREE(fname);
2380 TALLOC_FREE(smb_fname);
2381 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
2382 dptr_SeekDir(dirptr, prev_dirpos);
2383 return status;
2385 if (!NT_STATUS_IS_OK(status)) {
2386 return status;
2389 *_last_entry_off = last_entry_off;
2390 return NT_STATUS_OK;
2393 static NTSTATUS get_lanman2_dir_entry(TALLOC_CTX *ctx,
2394 connection_struct *conn,
2395 struct dptr_struct *dirptr,
2396 uint16 flags2,
2397 const char *path_mask,
2398 uint32 dirtype,
2399 int info_level,
2400 bool requires_resume_key,
2401 bool dont_descend,
2402 bool ask_sharemode,
2403 char **ppdata,
2404 char *base_data,
2405 char *end_data,
2406 int space_remaining,
2407 bool *got_exact_match,
2408 int *last_entry_off,
2409 struct ea_list *name_list)
2411 uint8_t align = 4;
2412 const bool do_pad = true;
2414 if (info_level >= 1 && info_level <= 3) {
2415 /* No alignment on earlier info levels. */
2416 align = 1;
2419 return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2,
2420 path_mask, dirtype, info_level,
2421 requires_resume_key, dont_descend, ask_sharemode,
2422 align, do_pad,
2423 ppdata, base_data, end_data,
2424 space_remaining,
2425 got_exact_match,
2426 last_entry_off, name_list);
2429 /****************************************************************************
2430 Reply to a TRANS2_FINDFIRST.
2431 ****************************************************************************/
2433 static void call_trans2findfirst(connection_struct *conn,
2434 struct smb_request *req,
2435 char **pparams, int total_params,
2436 char **ppdata, int total_data,
2437 unsigned int max_data_bytes)
2439 /* We must be careful here that we don't return more than the
2440 allowed number of data bytes. If this means returning fewer than
2441 maxentries then so be it. We assume that the redirector has
2442 enough room for the fixed number of parameter bytes it has
2443 requested. */
2444 struct smb_filename *smb_dname = NULL;
2445 char *params = *pparams;
2446 char *pdata = *ppdata;
2447 char *data_end;
2448 uint32 dirtype;
2449 int maxentries;
2450 uint16 findfirst_flags;
2451 bool close_after_first;
2452 bool close_if_end;
2453 bool requires_resume_key;
2454 int info_level;
2455 char *directory = NULL;
2456 char *mask = NULL;
2457 char *p;
2458 int last_entry_off=0;
2459 int dptr_num = -1;
2460 int numentries = 0;
2461 int i;
2462 bool finished = False;
2463 bool dont_descend = False;
2464 bool out_of_space = False;
2465 int space_remaining;
2466 bool mask_contains_wcard = False;
2467 struct ea_list *ea_list = NULL;
2468 NTSTATUS ntstatus = NT_STATUS_OK;
2469 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
2470 TALLOC_CTX *ctx = talloc_tos();
2471 struct dptr_struct *dirptr = NULL;
2472 struct smbd_server_connection *sconn = req->sconn;
2473 uint32_t ucf_flags = (UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP);
2474 bool backup_priv = false;
2476 if (total_params < 13) {
2477 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2478 goto out;
2481 dirtype = SVAL(params,0);
2482 maxentries = SVAL(params,2);
2483 findfirst_flags = SVAL(params,4);
2484 close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
2485 close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
2486 requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
2487 backup_priv = ((findfirst_flags & FLAG_TRANS2_FIND_BACKUP_INTENT) &&
2488 security_token_has_privilege(get_current_nttok(conn),
2489 SEC_PRIV_BACKUP));
2491 info_level = SVAL(params,6);
2493 DEBUG(3,("call_trans2findfirst: dirtype = %x, maxentries = %d, close_after_first=%d, \
2494 close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_data_bytes = %d\n",
2495 (unsigned int)dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
2496 (int)backup_priv,
2497 info_level, max_data_bytes));
2499 if (!maxentries) {
2500 /* W2K3 seems to treat zero as 1. */
2501 maxentries = 1;
2504 switch (info_level) {
2505 case SMB_FIND_INFO_STANDARD:
2506 case SMB_FIND_EA_SIZE:
2507 case SMB_FIND_EA_LIST:
2508 case SMB_FIND_FILE_DIRECTORY_INFO:
2509 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
2510 case SMB_FIND_FILE_NAMES_INFO:
2511 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
2512 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
2513 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
2514 break;
2515 case SMB_FIND_FILE_UNIX:
2516 case SMB_FIND_FILE_UNIX_INFO2:
2517 /* Always use filesystem for UNIX mtime query. */
2518 ask_sharemode = false;
2519 if (!lp_unix_extensions()) {
2520 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2521 goto out;
2523 ucf_flags |= UCF_UNIX_NAME_LOOKUP;
2524 break;
2525 default:
2526 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2527 goto out;
2530 srvstr_get_path_wcard(ctx, params, req->flags2, &directory,
2531 params+12, total_params - 12,
2532 STR_TERMINATE, &ntstatus, &mask_contains_wcard);
2533 if (!NT_STATUS_IS_OK(ntstatus)) {
2534 reply_nterror(req, ntstatus);
2535 goto out;
2538 if (backup_priv) {
2539 become_root();
2540 ntstatus = filename_convert_with_privilege(ctx,
2541 conn,
2542 req,
2543 directory,
2544 ucf_flags,
2545 &mask_contains_wcard,
2546 &smb_dname);
2547 } else {
2548 ntstatus = filename_convert(ctx, conn,
2549 req->flags2 & FLAGS2_DFS_PATHNAMES,
2550 directory,
2551 ucf_flags,
2552 &mask_contains_wcard,
2553 &smb_dname);
2556 if (!NT_STATUS_IS_OK(ntstatus)) {
2557 if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
2558 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2559 ERRSRV, ERRbadpath);
2560 goto out;
2562 reply_nterror(req, ntstatus);
2563 goto out;
2566 mask = smb_dname->original_lcomp;
2568 directory = smb_dname->base_name;
2570 p = strrchr_m(directory,'/');
2571 if(p == NULL) {
2572 /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */
2573 if((directory[0] == '.') && (directory[1] == '\0')) {
2574 mask = talloc_strdup(ctx,"*");
2575 if (!mask) {
2576 reply_nterror(req, NT_STATUS_NO_MEMORY);
2577 goto out;
2579 mask_contains_wcard = True;
2581 } else {
2582 *p = 0;
2585 if (p == NULL || p == directory) {
2586 /* Ensure we don't have a directory name of "". */
2587 directory = talloc_strdup(talloc_tos(), ".");
2588 if (!directory) {
2589 reply_nterror(req, NT_STATUS_NO_MEMORY);
2590 goto out;
2594 DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
2596 if (info_level == SMB_FIND_EA_LIST) {
2597 uint32 ea_size;
2599 if (total_data < 4) {
2600 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2601 goto out;
2604 ea_size = IVAL(pdata,0);
2605 if (ea_size != total_data) {
2606 DEBUG(4,("call_trans2findfirst: Rejecting EA request with incorrect \
2607 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2608 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2609 goto out;
2612 if (!lp_ea_support(SNUM(conn))) {
2613 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
2614 goto out;
2617 /* Pull out the list of names. */
2618 ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
2619 if (!ea_list) {
2620 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2621 goto out;
2625 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
2626 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2627 goto out;
2630 *ppdata = (char *)SMB_REALLOC(
2631 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2632 if(*ppdata == NULL ) {
2633 reply_nterror(req, NT_STATUS_NO_MEMORY);
2634 goto out;
2636 pdata = *ppdata;
2637 data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2639 /* Realloc the params space */
2640 *pparams = (char *)SMB_REALLOC(*pparams, 10);
2641 if (*pparams == NULL) {
2642 reply_nterror(req, NT_STATUS_NO_MEMORY);
2643 goto out;
2645 params = *pparams;
2647 /* Save the wildcard match and attribs we are using on this directory -
2648 needed as lanman2 assumes these are being saved between calls */
2650 ntstatus = dptr_create(conn,
2651 req,
2652 NULL, /* fsp */
2653 directory,
2654 False,
2655 True,
2656 req->smbpid,
2657 mask,
2658 mask_contains_wcard,
2659 dirtype,
2660 &dirptr);
2662 if (!NT_STATUS_IS_OK(ntstatus)) {
2663 reply_nterror(req, ntstatus);
2664 goto out;
2667 if (backup_priv) {
2668 /* Remember this in case we have
2669 to do a findnext. */
2670 dptr_set_priv(dirptr);
2673 dptr_num = dptr_dnum(dirptr);
2674 DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));
2676 /* Initialize per TRANS2_FIND_FIRST operation data */
2677 dptr_init_search_op(dirptr);
2679 /* We don't need to check for VOL here as this is returned by
2680 a different TRANS2 call. */
2682 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
2683 directory,lp_dont_descend(ctx, SNUM(conn))));
2684 if (in_list(directory,lp_dont_descend(ctx, SNUM(conn)),conn->case_sensitive))
2685 dont_descend = True;
2687 p = pdata;
2688 space_remaining = max_data_bytes;
2689 out_of_space = False;
2691 for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
2692 bool got_exact_match = False;
2694 /* this is a heuristic to avoid seeking the dirptr except when
2695 absolutely necessary. It allows for a filename of about 40 chars */
2696 if (space_remaining < DIRLEN_GUESS && numentries > 0) {
2697 out_of_space = True;
2698 finished = False;
2699 } else {
2700 ntstatus = get_lanman2_dir_entry(ctx,
2701 conn,
2702 dirptr,
2703 req->flags2,
2704 mask,dirtype,info_level,
2705 requires_resume_key,dont_descend,
2706 ask_sharemode,
2707 &p,pdata,data_end,
2708 space_remaining,
2709 &got_exact_match,
2710 &last_entry_off, ea_list);
2711 if (NT_STATUS_EQUAL(ntstatus,
2712 NT_STATUS_ILLEGAL_CHARACTER)) {
2714 * Bad character conversion on name. Ignore this
2715 * entry.
2717 continue;
2719 if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) {
2720 out_of_space = true;
2721 } else {
2722 finished = !NT_STATUS_IS_OK(ntstatus);
2726 if (!finished && !out_of_space)
2727 numentries++;
2730 * As an optimisation if we know we aren't looking
2731 * for a wildcard name (ie. the name matches the wildcard exactly)
2732 * then we can finish on any (first) match.
2733 * This speeds up large directory searches. JRA.
2736 if(got_exact_match)
2737 finished = True;
2739 /* Ensure space_remaining never goes -ve. */
2740 if (PTR_DIFF(p,pdata) > max_data_bytes) {
2741 space_remaining = 0;
2742 out_of_space = true;
2743 } else {
2744 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
2748 /* Check if we can close the dirptr */
2749 if(close_after_first || (finished && close_if_end)) {
2750 DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
2751 dptr_close(sconn, &dptr_num);
2755 * If there are no matching entries we must return ERRDOS/ERRbadfile -
2756 * from observation of NT. NB. This changes to ERRDOS,ERRnofiles if
2757 * the protocol level is less than NT1. Tested with smbclient. JRA.
2758 * This should fix the OS/2 client bug #2335.
2761 if(numentries == 0) {
2762 dptr_close(sconn, &dptr_num);
2763 if (get_Protocol() < PROTOCOL_NT1) {
2764 reply_force_doserror(req, ERRDOS, ERRnofiles);
2765 goto out;
2766 } else {
2767 reply_botherror(req, NT_STATUS_NO_SUCH_FILE,
2768 ERRDOS, ERRbadfile);
2769 goto out;
2773 /* At this point pdata points to numentries directory entries. */
2775 /* Set up the return parameter block */
2776 SSVAL(params,0,dptr_num);
2777 SSVAL(params,2,numentries);
2778 SSVAL(params,4,finished);
2779 SSVAL(params,6,0); /* Never an EA error */
2780 SSVAL(params,8,last_entry_off);
2782 send_trans2_replies(conn, req, NT_STATUS_OK, params, 10, pdata, PTR_DIFF(p,pdata),
2783 max_data_bytes);
2785 if ((! *directory) && dptr_path(sconn, dptr_num)) {
2786 directory = talloc_strdup(talloc_tos(),dptr_path(sconn, dptr_num));
2787 if (!directory) {
2788 reply_nterror(req, NT_STATUS_NO_MEMORY);
2792 DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
2793 smb_fn_name(req->cmd),
2794 mask, directory, dirtype, numentries ) );
2797 * Force a name mangle here to ensure that the
2798 * mask as an 8.3 name is top of the mangled cache.
2799 * The reasons for this are subtle. Don't remove
2800 * this code unless you know what you are doing
2801 * (see PR#13758). JRA.
2804 if(!mangle_is_8_3_wildcards( mask, False, conn->params)) {
2805 char mangled_name[13];
2806 name_to_8_3(mask, mangled_name, True, conn->params);
2808 out:
2810 if (backup_priv) {
2811 unbecome_root();
2814 TALLOC_FREE(smb_dname);
2815 return;
2818 /****************************************************************************
2819 Reply to a TRANS2_FINDNEXT.
2820 ****************************************************************************/
2822 static void call_trans2findnext(connection_struct *conn,
2823 struct smb_request *req,
2824 char **pparams, int total_params,
2825 char **ppdata, int total_data,
2826 unsigned int max_data_bytes)
2828 /* We must be careful here that we don't return more than the
2829 allowed number of data bytes. If this means returning fewer than
2830 maxentries then so be it. We assume that the redirector has
2831 enough room for the fixed number of parameter bytes it has
2832 requested. */
2833 char *params = *pparams;
2834 char *pdata = *ppdata;
2835 char *data_end;
2836 int dptr_num;
2837 int maxentries;
2838 uint16 info_level;
2839 uint32 resume_key;
2840 uint16 findnext_flags;
2841 bool close_after_request;
2842 bool close_if_end;
2843 bool requires_resume_key;
2844 bool continue_bit;
2845 bool mask_contains_wcard = False;
2846 char *resume_name = NULL;
2847 const char *mask = NULL;
2848 const char *directory = NULL;
2849 char *p = NULL;
2850 uint16 dirtype;
2851 int numentries = 0;
2852 int i, last_entry_off=0;
2853 bool finished = False;
2854 bool dont_descend = False;
2855 bool out_of_space = False;
2856 int space_remaining;
2857 struct ea_list *ea_list = NULL;
2858 NTSTATUS ntstatus = NT_STATUS_OK;
2859 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
2860 TALLOC_CTX *ctx = talloc_tos();
2861 struct dptr_struct *dirptr;
2862 struct smbd_server_connection *sconn = req->sconn;
2863 bool backup_priv = false;
2865 if (total_params < 13) {
2866 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2867 return;
2870 dptr_num = SVAL(params,0);
2871 maxentries = SVAL(params,2);
2872 info_level = SVAL(params,4);
2873 resume_key = IVAL(params,6);
2874 findnext_flags = SVAL(params,10);
2875 close_after_request = (findnext_flags & FLAG_TRANS2_FIND_CLOSE);
2876 close_if_end = (findnext_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
2877 requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
2878 continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE);
2880 if (!continue_bit) {
2881 /* We only need resume_name if continue_bit is zero. */
2882 srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name,
2883 params+12,
2884 total_params - 12, STR_TERMINATE, &ntstatus,
2885 &mask_contains_wcard);
2886 if (!NT_STATUS_IS_OK(ntstatus)) {
2887 /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
2888 complain (it thinks we're asking for the directory above the shared
2889 path or an invalid name). Catch this as the resume name is only compared, never used in
2890 a file access. JRA. */
2891 srvstr_pull_talloc(ctx, params, req->flags2,
2892 &resume_name, params+12,
2893 total_params - 12,
2894 STR_TERMINATE);
2896 if (!resume_name || !(ISDOT(resume_name) || ISDOTDOT(resume_name))) {
2897 reply_nterror(req, ntstatus);
2898 return;
2903 DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \
2904 close_after_request=%d, close_if_end = %d requires_resume_key = %d \
2905 resume_key = %d resume name = %s continue=%d level = %d\n",
2906 dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end,
2907 requires_resume_key, resume_key,
2908 resume_name ? resume_name : "(NULL)", continue_bit, info_level));
2910 if (!maxentries) {
2911 /* W2K3 seems to treat zero as 1. */
2912 maxentries = 1;
2915 switch (info_level) {
2916 case SMB_FIND_INFO_STANDARD:
2917 case SMB_FIND_EA_SIZE:
2918 case SMB_FIND_EA_LIST:
2919 case SMB_FIND_FILE_DIRECTORY_INFO:
2920 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
2921 case SMB_FIND_FILE_NAMES_INFO:
2922 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
2923 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
2924 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
2925 break;
2926 case SMB_FIND_FILE_UNIX:
2927 case SMB_FIND_FILE_UNIX_INFO2:
2928 /* Always use filesystem for UNIX mtime query. */
2929 ask_sharemode = false;
2930 if (!lp_unix_extensions()) {
2931 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2932 return;
2934 break;
2935 default:
2936 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2937 return;
2940 if (info_level == SMB_FIND_EA_LIST) {
2941 uint32 ea_size;
2943 if (total_data < 4) {
2944 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2945 return;
2948 ea_size = IVAL(pdata,0);
2949 if (ea_size != total_data) {
2950 DEBUG(4,("call_trans2findnext: Rejecting EA request with incorrect \
2951 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2952 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2953 return;
2956 if (!lp_ea_support(SNUM(conn))) {
2957 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
2958 return;
2961 /* Pull out the list of names. */
2962 ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
2963 if (!ea_list) {
2964 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2965 return;
2969 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
2970 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2971 return;
2974 *ppdata = (char *)SMB_REALLOC(
2975 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2976 if(*ppdata == NULL) {
2977 reply_nterror(req, NT_STATUS_NO_MEMORY);
2978 return;
2981 pdata = *ppdata;
2982 data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2984 /* Realloc the params space */
2985 *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD);
2986 if(*pparams == NULL ) {
2987 reply_nterror(req, NT_STATUS_NO_MEMORY);
2988 return;
2991 params = *pparams;
2993 /* Check that the dptr is valid */
2994 if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) {
2995 reply_nterror(req, STATUS_NO_MORE_FILES);
2996 return;
2999 directory = dptr_path(sconn, dptr_num);
3001 /* Get the wildcard mask from the dptr */
3002 if((mask = dptr_wcard(sconn, dptr_num))== NULL) {
3003 DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
3004 reply_nterror(req, STATUS_NO_MORE_FILES);
3005 return;
3008 /* Get the attr mask from the dptr */
3009 dirtype = dptr_attr(sconn, dptr_num);
3011 backup_priv = dptr_get_priv(dirptr);
3013 DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld) "
3014 "backup_priv = %d\n",
3015 dptr_num, mask, dirtype,
3016 (long)dirptr,
3017 dptr_TellDir(dirptr),
3018 (int)backup_priv));
3020 /* Initialize per TRANS2_FIND_NEXT operation data */
3021 dptr_init_search_op(dirptr);
3023 /* We don't need to check for VOL here as this is returned by
3024 a different TRANS2 call. */
3026 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
3027 directory,lp_dont_descend(ctx, SNUM(conn))));
3028 if (in_list(directory,lp_dont_descend(ctx, SNUM(conn)),conn->case_sensitive))
3029 dont_descend = True;
3031 p = pdata;
3032 space_remaining = max_data_bytes;
3033 out_of_space = False;
3035 if (backup_priv) {
3036 become_root();
3040 * Seek to the correct position. We no longer use the resume key but
3041 * depend on the last file name instead.
3044 if(!continue_bit && resume_name && *resume_name) {
3045 SMB_STRUCT_STAT st;
3047 long current_pos = 0;
3049 * Remember, name_to_8_3 is called by
3050 * get_lanman2_dir_entry(), so the resume name
3051 * could be mangled. Ensure we check the unmangled name.
3054 if (mangle_is_mangled(resume_name, conn->params)) {
3055 char *new_resume_name = NULL;
3056 mangle_lookup_name_from_8_3(ctx,
3057 resume_name,
3058 &new_resume_name,
3059 conn->params);
3060 if (new_resume_name) {
3061 resume_name = new_resume_name;
3066 * Fix for NT redirector problem triggered by resume key indexes
3067 * changing between directory scans. We now return a resume key of 0
3068 * and instead look for the filename to continue from (also given
3069 * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
3070 * findfirst/findnext (as is usual) then the directory pointer
3071 * should already be at the correct place.
3074 finished = !dptr_SearchDir(dirptr, resume_name, &current_pos, &st);
3075 } /* end if resume_name && !continue_bit */
3077 for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
3078 bool got_exact_match = False;
3080 /* this is a heuristic to avoid seeking the dirptr except when
3081 absolutely necessary. It allows for a filename of about 40 chars */
3082 if (space_remaining < DIRLEN_GUESS && numentries > 0) {
3083 out_of_space = True;
3084 finished = False;
3085 } else {
3086 ntstatus = get_lanman2_dir_entry(ctx,
3087 conn,
3088 dirptr,
3089 req->flags2,
3090 mask,dirtype,info_level,
3091 requires_resume_key,dont_descend,
3092 ask_sharemode,
3093 &p,pdata,data_end,
3094 space_remaining,
3095 &got_exact_match,
3096 &last_entry_off, ea_list);
3097 if (NT_STATUS_EQUAL(ntstatus,
3098 NT_STATUS_ILLEGAL_CHARACTER)) {
3100 * Bad character conversion on name. Ignore this
3101 * entry.
3103 continue;
3105 if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) {
3106 out_of_space = true;
3107 } else {
3108 finished = !NT_STATUS_IS_OK(ntstatus);
3112 if (!finished && !out_of_space)
3113 numentries++;
3116 * As an optimisation if we know we aren't looking
3117 * for a wildcard name (ie. the name matches the wildcard exactly)
3118 * then we can finish on any (first) match.
3119 * This speeds up large directory searches. JRA.
3122 if(got_exact_match)
3123 finished = True;
3125 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
3128 DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
3129 smb_fn_name(req->cmd),
3130 mask, directory, dirtype, numentries ) );
3132 /* Check if we can close the dirptr */
3133 if(close_after_request || (finished && close_if_end)) {
3134 DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
3135 dptr_close(sconn, &dptr_num); /* This frees up the saved mask */
3138 if (backup_priv) {
3139 unbecome_root();
3142 /* Set up the return parameter block */
3143 SSVAL(params,0,numentries);
3144 SSVAL(params,2,finished);
3145 SSVAL(params,4,0); /* Never an EA error */
3146 SSVAL(params,6,last_entry_off);
3148 send_trans2_replies(conn, req, NT_STATUS_OK, params, 8, pdata, PTR_DIFF(p,pdata),
3149 max_data_bytes);
3151 return;
3154 unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
3156 E_md4hash(lp_servicename(talloc_tos(), SNUM(conn)),objid);
3157 return objid;
3160 static void samba_extended_info_version(struct smb_extended_info *extended_info)
3162 SMB_ASSERT(extended_info != NULL);
3164 extended_info->samba_magic = SAMBA_EXTENDED_INFO_MAGIC;
3165 extended_info->samba_version = ((SAMBA_VERSION_MAJOR & 0xff) << 24)
3166 | ((SAMBA_VERSION_MINOR & 0xff) << 16)
3167 | ((SAMBA_VERSION_RELEASE & 0xff) << 8);
3168 #ifdef SAMBA_VERSION_REVISION
3169 extended_info->samba_version |= (tolower(*SAMBA_VERSION_REVISION) - 'a' + 1) & 0xff;
3170 #endif
3171 extended_info->samba_subversion = 0;
3172 #ifdef SAMBA_VERSION_RC_RELEASE
3173 extended_info->samba_subversion |= (SAMBA_VERSION_RC_RELEASE & 0xff) << 24;
3174 #else
3175 #ifdef SAMBA_VERSION_PRE_RELEASE
3176 extended_info->samba_subversion |= (SAMBA_VERSION_PRE_RELEASE & 0xff) << 16;
3177 #endif
3178 #endif
3179 #ifdef SAMBA_VERSION_VENDOR_PATCH
3180 extended_info->samba_subversion |= (SAMBA_VERSION_VENDOR_PATCH & 0xffff);
3181 #endif
3182 extended_info->samba_gitcommitdate = 0;
3183 #ifdef SAMBA_VERSION_COMMIT_TIME
3184 unix_to_nt_time(&extended_info->samba_gitcommitdate, SAMBA_VERSION_COMMIT_TIME);
3185 #endif
3187 memset(extended_info->samba_version_string, 0,
3188 sizeof(extended_info->samba_version_string));
3190 snprintf (extended_info->samba_version_string,
3191 sizeof(extended_info->samba_version_string),
3192 "%s", samba_version_string());
3195 NTSTATUS smbd_do_qfsinfo(struct smbXsrv_connection *xconn,
3196 connection_struct *conn,
3197 TALLOC_CTX *mem_ctx,
3198 uint16_t info_level,
3199 uint16_t flags2,
3200 unsigned int max_data_bytes,
3201 size_t *fixed_portion,
3202 struct smb_filename *fname,
3203 char **ppdata,
3204 int *ret_data_len)
3206 char *pdata, *end_data;
3207 int data_len = 0;
3208 size_t len = 0;
3209 const char *vname = volume_label(talloc_tos(), SNUM(conn));
3210 int snum = SNUM(conn);
3211 const char *fstype = lp_fstype(SNUM(conn));
3212 const char *filename = NULL;
3213 uint32 additional_flags = 0;
3214 struct smb_filename smb_fname;
3215 SMB_STRUCT_STAT st;
3216 NTSTATUS status = NT_STATUS_OK;
3218 if (fname == NULL || fname->base_name == NULL) {
3219 filename = ".";
3220 } else {
3221 filename = fname->base_name;
3224 if (IS_IPC(conn)) {
3225 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
3226 DEBUG(0,("smbd_do_qfsinfo: not an allowed "
3227 "info level (0x%x) on IPC$.\n",
3228 (unsigned int)info_level));
3229 return NT_STATUS_ACCESS_DENIED;
3233 DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level));
3235 ZERO_STRUCT(smb_fname);
3236 smb_fname.base_name = discard_const_p(char, filename);
3238 if(SMB_VFS_STAT(conn, &smb_fname) != 0) {
3239 DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
3240 return map_nt_error_from_unix(errno);
3243 st = smb_fname.st;
3245 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
3246 return NT_STATUS_INVALID_PARAMETER;
3249 *ppdata = (char *)SMB_REALLOC(
3250 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
3251 if (*ppdata == NULL) {
3252 return NT_STATUS_NO_MEMORY;
3255 pdata = *ppdata;
3256 memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
3257 end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
3259 *fixed_portion = 0;
3261 switch (info_level) {
3262 case SMB_INFO_ALLOCATION:
3264 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
3265 data_len = 18;
3266 if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
3267 return map_nt_error_from_unix(errno);
3270 block_size = lp_block_size(snum);
3271 if (bsize < block_size) {
3272 uint64_t factor = block_size/bsize;
3273 bsize = block_size;
3274 dsize /= factor;
3275 dfree /= factor;
3277 if (bsize > block_size) {
3278 uint64_t factor = bsize/block_size;
3279 bsize = block_size;
3280 dsize *= factor;
3281 dfree *= factor;
3283 bytes_per_sector = 512;
3284 sectors_per_unit = bsize/bytes_per_sector;
3286 DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
3287 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
3288 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
3290 SIVAL(pdata,l1_idFileSystem,st.st_ex_dev);
3291 SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
3292 SIVAL(pdata,l1_cUnit,dsize);
3293 SIVAL(pdata,l1_cUnitAvail,dfree);
3294 SSVAL(pdata,l1_cbSector,bytes_per_sector);
3295 break;
3298 case SMB_INFO_VOLUME:
3299 /* Return volume name */
3301 * Add volume serial number - hash of a combination of
3302 * the called hostname and the service name.
3304 SIVAL(pdata,0,str_checksum(lp_servicename(talloc_tos(), snum)) ^ (str_checksum(get_local_machine_name())<<16) );
3306 * Win2k3 and previous mess this up by sending a name length
3307 * one byte short. I believe only older clients (OS/2 Win9x) use
3308 * this call so try fixing this by adding a terminating null to
3309 * the pushed string. The change here was adding the STR_TERMINATE. JRA.
3311 status = srvstr_push(
3312 pdata, flags2,
3313 pdata+l2_vol_szVolLabel, vname,
3314 PTR_DIFF(end_data, pdata+l2_vol_szVolLabel),
3315 STR_NOALIGN|STR_TERMINATE, &len);
3316 if (!NT_STATUS_IS_OK(status)) {
3317 return status;
3319 SCVAL(pdata,l2_vol_cch,len);
3320 data_len = l2_vol_szVolLabel + len;
3321 DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %u, name = %s\n",
3322 (unsigned)convert_timespec_to_time_t(st.st_ex_ctime),
3323 (unsigned)len, vname));
3324 break;
3326 case SMB_QUERY_FS_ATTRIBUTE_INFO:
3327 case SMB_FS_ATTRIBUTE_INFORMATION:
3329 additional_flags = 0;
3330 #if defined(HAVE_SYS_QUOTAS)
3331 additional_flags |= FILE_VOLUME_QUOTAS;
3332 #endif
3334 if(lp_nt_acl_support(SNUM(conn))) {
3335 additional_flags |= FILE_PERSISTENT_ACLS;
3338 /* Capabilities are filled in at connection time through STATVFS call */
3339 additional_flags |= conn->fs_capabilities;
3340 additional_flags |= lp_parm_int(conn->params->service,
3341 "share", "fake_fscaps",
3344 SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
3345 FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
3346 additional_flags); /* FS ATTRIBUTES */
3348 SIVAL(pdata,4,255); /* Max filename component length */
3349 /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
3350 and will think we can't do long filenames */
3351 status = srvstr_push(pdata, flags2, pdata+12, fstype,
3352 PTR_DIFF(end_data, pdata+12),
3353 STR_UNICODE, &len);
3354 if (!NT_STATUS_IS_OK(status)) {
3355 return status;
3357 SIVAL(pdata,8,len);
3358 data_len = 12 + len;
3359 if (max_data_bytes >= 16 && data_len > max_data_bytes) {
3360 /* the client only requested a portion of the
3361 file system name */
3362 data_len = max_data_bytes;
3363 status = STATUS_BUFFER_OVERFLOW;
3365 *fixed_portion = 16;
3366 break;
3368 case SMB_QUERY_FS_LABEL_INFO:
3369 case SMB_FS_LABEL_INFORMATION:
3370 status = srvstr_push(pdata, flags2, pdata+4, vname,
3371 PTR_DIFF(end_data, pdata+4), 0, &len);
3372 if (!NT_STATUS_IS_OK(status)) {
3373 return status;
3375 data_len = 4 + len;
3376 SIVAL(pdata,0,len);
3377 break;
3379 case SMB_QUERY_FS_VOLUME_INFO:
3380 case SMB_FS_VOLUME_INFORMATION:
3383 * Add volume serial number - hash of a combination of
3384 * the called hostname and the service name.
3386 SIVAL(pdata,8,str_checksum(lp_servicename(talloc_tos(), snum)) ^
3387 (str_checksum(get_local_machine_name())<<16));
3389 /* Max label len is 32 characters. */
3390 status = srvstr_push(pdata, flags2, pdata+18, vname,
3391 PTR_DIFF(end_data, pdata+18),
3392 STR_UNICODE, &len);
3393 if (!NT_STATUS_IS_OK(status)) {
3394 return status;
3396 SIVAL(pdata,12,len);
3397 data_len = 18+len;
3399 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
3400 (int)strlen(vname),vname,
3401 lp_servicename(talloc_tos(), snum)));
3402 if (max_data_bytes >= 24 && data_len > max_data_bytes) {
3403 /* the client only requested a portion of the
3404 volume label */
3405 data_len = max_data_bytes;
3406 status = STATUS_BUFFER_OVERFLOW;
3408 *fixed_portion = 24;
3409 break;
3411 case SMB_QUERY_FS_SIZE_INFO:
3412 case SMB_FS_SIZE_INFORMATION:
3414 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
3415 data_len = 24;
3416 if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
3417 return map_nt_error_from_unix(errno);
3419 block_size = lp_block_size(snum);
3420 if (bsize < block_size) {
3421 uint64_t factor = block_size/bsize;
3422 bsize = block_size;
3423 dsize /= factor;
3424 dfree /= factor;
3426 if (bsize > block_size) {
3427 uint64_t factor = bsize/block_size;
3428 bsize = block_size;
3429 dsize *= factor;
3430 dfree *= factor;
3432 bytes_per_sector = 512;
3433 sectors_per_unit = bsize/bytes_per_sector;
3434 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
3435 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
3436 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
3437 SBIG_UINT(pdata,0,dsize);
3438 SBIG_UINT(pdata,8,dfree);
3439 SIVAL(pdata,16,sectors_per_unit);
3440 SIVAL(pdata,20,bytes_per_sector);
3441 *fixed_portion = 24;
3442 break;
3445 case SMB_FS_FULL_SIZE_INFORMATION:
3447 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
3448 data_len = 32;
3449 if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
3450 return map_nt_error_from_unix(errno);
3452 block_size = lp_block_size(snum);
3453 if (bsize < block_size) {
3454 uint64_t factor = block_size/bsize;
3455 bsize = block_size;
3456 dsize /= factor;
3457 dfree /= factor;
3459 if (bsize > block_size) {
3460 uint64_t factor = bsize/block_size;
3461 bsize = block_size;
3462 dsize *= factor;
3463 dfree *= factor;
3465 bytes_per_sector = 512;
3466 sectors_per_unit = bsize/bytes_per_sector;
3467 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
3468 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
3469 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
3470 SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
3471 SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
3472 SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
3473 SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
3474 SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
3475 *fixed_portion = 32;
3476 break;
3479 case SMB_QUERY_FS_DEVICE_INFO:
3480 case SMB_FS_DEVICE_INFORMATION:
3482 uint32_t characteristics = FILE_DEVICE_IS_MOUNTED;
3484 if (!CAN_WRITE(conn)) {
3485 characteristics |= FILE_READ_ONLY_DEVICE;
3487 data_len = 8;
3488 SIVAL(pdata,0,FILE_DEVICE_DISK); /* dev type */
3489 SIVAL(pdata,4,characteristics);
3490 *fixed_portion = 8;
3491 break;
3494 #ifdef HAVE_SYS_QUOTAS
3495 case SMB_FS_QUOTA_INFORMATION:
3497 * what we have to send --metze:
3499 * Unknown1: 24 NULL bytes
3500 * Soft Quota Treshold: 8 bytes seems like uint64_t or so
3501 * Hard Quota Limit: 8 bytes seems like uint64_t or so
3502 * Quota Flags: 2 byte :
3503 * Unknown3: 6 NULL bytes
3505 * 48 bytes total
3507 * details for Quota Flags:
3509 * 0x0020 Log Limit: log if the user exceeds his Hard Quota
3510 * 0x0010 Log Warn: log if the user exceeds his Soft Quota
3511 * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
3512 * 0x0001 Enable Quotas: enable quota for this fs
3516 /* we need to fake up a fsp here,
3517 * because its not send in this call
3519 files_struct fsp;
3520 SMB_NTQUOTA_STRUCT quotas;
3522 ZERO_STRUCT(fsp);
3523 ZERO_STRUCT(quotas);
3525 fsp.conn = conn;
3526 fsp.fnum = FNUM_FIELD_INVALID;
3528 /* access check */
3529 if (get_current_uid(conn) != 0) {
3530 DEBUG(0,("get_user_quota: access_denied "
3531 "service [%s] user [%s]\n",
3532 lp_servicename(talloc_tos(), SNUM(conn)),
3533 conn->session_info->unix_info->unix_name));
3534 return NT_STATUS_ACCESS_DENIED;
3537 if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
3538 DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), SNUM(conn))));
3539 return map_nt_error_from_unix(errno);
3542 data_len = 48;
3544 DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",
3545 lp_servicename(talloc_tos(), SNUM(conn))));
3547 /* Unknown1 24 NULL bytes*/
3548 SBIG_UINT(pdata,0,(uint64_t)0);
3549 SBIG_UINT(pdata,8,(uint64_t)0);
3550 SBIG_UINT(pdata,16,(uint64_t)0);
3552 /* Default Soft Quota 8 bytes */
3553 SBIG_UINT(pdata,24,quotas.softlim);
3555 /* Default Hard Quota 8 bytes */
3556 SBIG_UINT(pdata,32,quotas.hardlim);
3558 /* Quota flag 2 bytes */
3559 SSVAL(pdata,40,quotas.qflags);
3561 /* Unknown3 6 NULL bytes */
3562 SSVAL(pdata,42,0);
3563 SIVAL(pdata,44,0);
3565 break;
3567 #endif /* HAVE_SYS_QUOTAS */
3568 case SMB_FS_OBJECTID_INFORMATION:
3570 unsigned char objid[16];
3571 struct smb_extended_info extended_info;
3572 memcpy(pdata,create_volume_objectid(conn, objid),16);
3573 samba_extended_info_version (&extended_info);
3574 SIVAL(pdata,16,extended_info.samba_magic);
3575 SIVAL(pdata,20,extended_info.samba_version);
3576 SIVAL(pdata,24,extended_info.samba_subversion);
3577 SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
3578 memcpy(pdata+36,extended_info.samba_version_string,28);
3579 data_len = 64;
3580 break;
3584 * Query the version and capabilities of the CIFS UNIX extensions
3585 * in use.
3588 case SMB_QUERY_CIFS_UNIX_INFO:
3590 bool large_write = lp_min_receive_file_size() &&
3591 !srv_is_signing_active(xconn);
3592 bool large_read = !srv_is_signing_active(xconn);
3593 int encrypt_caps = 0;
3595 if (!lp_unix_extensions()) {
3596 return NT_STATUS_INVALID_LEVEL;
3599 switch (conn->encrypt_level) {
3600 case SMB_SIGNING_OFF:
3601 encrypt_caps = 0;
3602 break;
3603 case SMB_SIGNING_IF_REQUIRED:
3604 case SMB_SIGNING_DEFAULT:
3605 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
3606 break;
3607 case SMB_SIGNING_REQUIRED:
3608 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
3609 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
3610 large_write = false;
3611 large_read = false;
3612 break;
3615 data_len = 12;
3616 SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
3617 SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
3619 /* We have POSIX ACLs, pathname, encryption,
3620 * large read/write, and locking capability. */
3622 SBIG_UINT(pdata,4,((uint64_t)(
3623 CIFS_UNIX_POSIX_ACLS_CAP|
3624 CIFS_UNIX_POSIX_PATHNAMES_CAP|
3625 CIFS_UNIX_FCNTL_LOCKS_CAP|
3626 CIFS_UNIX_EXTATTR_CAP|
3627 CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
3628 encrypt_caps|
3629 (large_read ? CIFS_UNIX_LARGE_READ_CAP : 0) |
3630 (large_write ?
3631 CIFS_UNIX_LARGE_WRITE_CAP : 0))));
3632 break;
3635 case SMB_QUERY_POSIX_FS_INFO:
3637 int rc;
3638 vfs_statvfs_struct svfs;
3640 if (!lp_unix_extensions()) {
3641 return NT_STATUS_INVALID_LEVEL;
3644 rc = SMB_VFS_STATVFS(conn, filename, &svfs);
3646 if (!rc) {
3647 data_len = 56;
3648 SIVAL(pdata,0,svfs.OptimalTransferSize);
3649 SIVAL(pdata,4,svfs.BlockSize);
3650 SBIG_UINT(pdata,8,svfs.TotalBlocks);
3651 SBIG_UINT(pdata,16,svfs.BlocksAvail);
3652 SBIG_UINT(pdata,24,svfs.UserBlocksAvail);
3653 SBIG_UINT(pdata,32,svfs.TotalFileNodes);
3654 SBIG_UINT(pdata,40,svfs.FreeFileNodes);
3655 SBIG_UINT(pdata,48,svfs.FsIdentifier);
3656 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
3657 #ifdef EOPNOTSUPP
3658 } else if (rc == EOPNOTSUPP) {
3659 return NT_STATUS_INVALID_LEVEL;
3660 #endif /* EOPNOTSUPP */
3661 } else {
3662 DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(talloc_tos(), SNUM(conn))));
3663 return NT_STATUS_DOS(ERRSRV, ERRerror);
3665 break;
3668 case SMB_QUERY_POSIX_WHOAMI:
3670 uint32_t flags = 0;
3671 uint32_t sid_bytes;
3672 int i;
3674 if (!lp_unix_extensions()) {
3675 return NT_STATUS_INVALID_LEVEL;
3678 if (max_data_bytes < 40) {
3679 return NT_STATUS_BUFFER_TOO_SMALL;
3682 if (security_session_user_level(conn->session_info, NULL) < SECURITY_USER) {
3683 flags |= SMB_WHOAMI_GUEST;
3686 /* NOTE: 8 bytes for UID/GID, irrespective of native
3687 * platform size. This matches
3688 * SMB_QUERY_FILE_UNIX_BASIC and friends.
3690 data_len = 4 /* flags */
3691 + 4 /* flag mask */
3692 + 8 /* uid */
3693 + 8 /* gid */
3694 + 4 /* ngroups */
3695 + 4 /* num_sids */
3696 + 4 /* SID bytes */
3697 + 4 /* pad/reserved */
3698 + (conn->session_info->unix_token->ngroups * 8)
3699 /* groups list */
3700 + (conn->session_info->security_token->num_sids *
3701 SID_MAX_SIZE)
3702 /* SID list */;
3704 SIVAL(pdata, 0, flags);
3705 SIVAL(pdata, 4, SMB_WHOAMI_MASK);
3706 SBIG_UINT(pdata, 8,
3707 (uint64_t)conn->session_info->unix_token->uid);
3708 SBIG_UINT(pdata, 16,
3709 (uint64_t)conn->session_info->unix_token->gid);
3712 if (data_len >= max_data_bytes) {
3713 /* Potential overflow, skip the GIDs and SIDs. */
3715 SIVAL(pdata, 24, 0); /* num_groups */
3716 SIVAL(pdata, 28, 0); /* num_sids */
3717 SIVAL(pdata, 32, 0); /* num_sid_bytes */
3718 SIVAL(pdata, 36, 0); /* reserved */
3720 data_len = 40;
3721 break;
3724 SIVAL(pdata, 24, conn->session_info->unix_token->ngroups);
3725 SIVAL(pdata, 28, conn->session_info->security_token->num_sids);
3727 /* We walk the SID list twice, but this call is fairly
3728 * infrequent, and I don't expect that it's performance
3729 * sensitive -- jpeach
3731 for (i = 0, sid_bytes = 0;
3732 i < conn->session_info->security_token->num_sids; ++i) {
3733 sid_bytes += ndr_size_dom_sid(
3734 &conn->session_info->security_token->sids[i],
3738 /* SID list byte count */
3739 SIVAL(pdata, 32, sid_bytes);
3741 /* 4 bytes pad/reserved - must be zero */
3742 SIVAL(pdata, 36, 0);
3743 data_len = 40;
3745 /* GID list */
3746 for (i = 0; i < conn->session_info->unix_token->ngroups; ++i) {
3747 SBIG_UINT(pdata, data_len,
3748 (uint64_t)conn->session_info->unix_token->groups[i]);
3749 data_len += 8;
3752 /* SID list */
3753 for (i = 0;
3754 i < conn->session_info->security_token->num_sids; ++i) {
3755 int sid_len = ndr_size_dom_sid(
3756 &conn->session_info->security_token->sids[i],
3759 sid_linearize(pdata + data_len, sid_len,
3760 &conn->session_info->security_token->sids[i]);
3761 data_len += sid_len;
3764 break;
3767 case SMB_MAC_QUERY_FS_INFO:
3769 * Thursby MAC extension... ONLY on NTFS filesystems
3770 * once we do streams then we don't need this
3772 if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
3773 data_len = 88;
3774 SIVAL(pdata,84,0x100); /* Don't support mac... */
3775 break;
3777 /* drop through */
3778 default:
3779 return NT_STATUS_INVALID_LEVEL;
3782 *ret_data_len = data_len;
3783 return status;
3786 /****************************************************************************
3787 Reply to a TRANS2_QFSINFO (query filesystem info).
3788 ****************************************************************************/
3790 static void call_trans2qfsinfo(connection_struct *conn,
3791 struct smb_request *req,
3792 char **pparams, int total_params,
3793 char **ppdata, int total_data,
3794 unsigned int max_data_bytes)
3796 char *params = *pparams;
3797 uint16_t info_level;
3798 int data_len = 0;
3799 size_t fixed_portion;
3800 NTSTATUS status;
3802 if (total_params < 2) {
3803 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3804 return;
3807 info_level = SVAL(params,0);
3809 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
3810 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
3811 DEBUG(0,("call_trans2qfsinfo: encryption required "
3812 "and info level 0x%x sent.\n",
3813 (unsigned int)info_level));
3814 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3815 return;
3819 DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
3821 status = smbd_do_qfsinfo(req->xconn, conn, req,
3822 info_level,
3823 req->flags2,
3824 max_data_bytes,
3825 &fixed_portion,
3826 NULL,
3827 ppdata, &data_len);
3828 if (!NT_STATUS_IS_OK(status)) {
3829 reply_nterror(req, status);
3830 return;
3833 send_trans2_replies(conn, req, NT_STATUS_OK, params, 0, *ppdata, data_len,
3834 max_data_bytes);
3836 DEBUG( 4, ( "%s info_level = %d\n",
3837 smb_fn_name(req->cmd), info_level) );
3839 return;
3842 /****************************************************************************
3843 Reply to a TRANS2_SETFSINFO (set filesystem info).
3844 ****************************************************************************/
3846 static void call_trans2setfsinfo(connection_struct *conn,
3847 struct smb_request *req,
3848 char **pparams, int total_params,
3849 char **ppdata, int total_data,
3850 unsigned int max_data_bytes)
3852 struct smbXsrv_connection *xconn = req->xconn;
3853 char *pdata = *ppdata;
3854 char *params = *pparams;
3855 uint16 info_level;
3857 DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",
3858 lp_servicename(talloc_tos(), SNUM(conn))));
3860 /* */
3861 if (total_params < 4) {
3862 DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
3863 total_params));
3864 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3865 return;
3868 info_level = SVAL(params,2);
3870 if (IS_IPC(conn)) {
3871 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION &&
3872 info_level != SMB_SET_CIFS_UNIX_INFO) {
3873 DEBUG(0,("call_trans2setfsinfo: not an allowed "
3874 "info level (0x%x) on IPC$.\n",
3875 (unsigned int)info_level));
3876 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3877 return;
3881 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
3882 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION) {
3883 DEBUG(0,("call_trans2setfsinfo: encryption required "
3884 "and info level 0x%x sent.\n",
3885 (unsigned int)info_level));
3886 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3887 return;
3891 switch(info_level) {
3892 case SMB_SET_CIFS_UNIX_INFO:
3893 if (!lp_unix_extensions()) {
3894 DEBUG(2,("call_trans2setfsinfo: "
3895 "SMB_SET_CIFS_UNIX_INFO is invalid with "
3896 "unix extensions off\n"));
3897 reply_nterror(req,
3898 NT_STATUS_INVALID_LEVEL);
3899 return;
3902 /* There should be 12 bytes of capabilities set. */
3903 if (total_data < 12) {
3904 reply_nterror(
3905 req,
3906 NT_STATUS_INVALID_PARAMETER);
3907 return;
3909 xconn->smb1.unix_info.client_major = SVAL(pdata,0);
3910 xconn->smb1.unix_info.client_minor = SVAL(pdata,2);
3911 xconn->smb1.unix_info.client_cap_low = IVAL(pdata,4);
3912 xconn->smb1.unix_info.client_cap_high = IVAL(pdata,8);
3913 /* Just print these values for now. */
3914 DEBUG(10, ("call_trans2setfsinfo: set unix_info info. "
3915 "major = %u, minor = %u cap_low = 0x%x, "
3916 "cap_high = 0x%xn",
3917 (unsigned int)xconn->
3918 smb1.unix_info.client_major,
3919 (unsigned int)xconn->
3920 smb1.unix_info.client_minor,
3921 (unsigned int)xconn->
3922 smb1.unix_info.client_cap_low,
3923 (unsigned int)xconn->
3924 smb1.unix_info.client_cap_high));
3926 /* Here is where we must switch to posix pathname processing... */
3927 if (xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3928 lp_set_posix_pathnames();
3929 mangle_change_to_posix();
3932 if ((xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) &&
3933 !(xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) {
3934 /* Client that knows how to do posix locks,
3935 * but not posix open/mkdir operations. Set a
3936 * default type for read/write checks. */
3938 lp_set_posix_default_cifsx_readwrite_locktype(POSIX_LOCK);
3941 break;
3943 case SMB_REQUEST_TRANSPORT_ENCRYPTION:
3945 NTSTATUS status;
3946 size_t param_len = 0;
3947 size_t data_len = total_data;
3949 if (!lp_unix_extensions()) {
3950 reply_nterror(
3951 req,
3952 NT_STATUS_INVALID_LEVEL);
3953 return;
3956 if (lp_smb_encrypt(SNUM(conn)) == SMB_SIGNING_OFF) {
3957 reply_nterror(
3958 req,
3959 NT_STATUS_NOT_SUPPORTED);
3960 return;
3963 if (xconn->smb1.echo_handler.trusted_fde) {
3964 DEBUG( 2,("call_trans2setfsinfo: "
3965 "request transport encryption disabled"
3966 "with 'fork echo handler = yes'\n"));
3967 reply_nterror(
3968 req,
3969 NT_STATUS_NOT_SUPPORTED);
3970 return;
3973 DEBUG( 4,("call_trans2setfsinfo: "
3974 "request transport encryption.\n"));
3976 status = srv_request_encryption_setup(conn,
3977 (unsigned char **)ppdata,
3978 &data_len,
3979 (unsigned char **)pparams,
3980 &param_len);
3982 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
3983 !NT_STATUS_IS_OK(status)) {
3984 reply_nterror(req, status);
3985 return;
3988 send_trans2_replies(conn, req,
3989 NT_STATUS_OK,
3990 *pparams,
3991 param_len,
3992 *ppdata,
3993 data_len,
3994 max_data_bytes);
3996 if (NT_STATUS_IS_OK(status)) {
3997 /* Server-side transport
3998 * encryption is now *on*. */
3999 status = srv_encryption_start(conn);
4000 if (!NT_STATUS_IS_OK(status)) {
4001 char *reason = talloc_asprintf(talloc_tos(),
4002 "Failure in setting "
4003 "up encrypted transport: %s",
4004 nt_errstr(status));
4005 exit_server_cleanly(reason);
4008 return;
4011 case SMB_FS_QUOTA_INFORMATION:
4013 files_struct *fsp = NULL;
4014 SMB_NTQUOTA_STRUCT quotas;
4016 ZERO_STRUCT(quotas);
4018 /* access check */
4019 if ((get_current_uid(conn) != 0) || !CAN_WRITE(conn)) {
4020 DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
4021 lp_servicename(talloc_tos(), SNUM(conn)),
4022 conn->session_info->unix_info->unix_name));
4023 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
4024 return;
4027 /* note: normaly there're 48 bytes,
4028 * but we didn't use the last 6 bytes for now
4029 * --metze
4031 fsp = file_fsp(req, SVAL(params,0));
4033 if (!check_fsp_ntquota_handle(conn, req,
4034 fsp)) {
4035 DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
4036 reply_nterror(
4037 req, NT_STATUS_INVALID_HANDLE);
4038 return;
4041 if (total_data < 42) {
4042 DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n",
4043 total_data));
4044 reply_nterror(
4045 req,
4046 NT_STATUS_INVALID_PARAMETER);
4047 return;
4050 /* unknown_1 24 NULL bytes in pdata*/
4052 /* the soft quotas 8 bytes (uint64_t)*/
4053 quotas.softlim = BVAL(pdata,24);
4055 /* the hard quotas 8 bytes (uint64_t)*/
4056 quotas.hardlim = BVAL(pdata,32);
4058 /* quota_flags 2 bytes **/
4059 quotas.qflags = SVAL(pdata,40);
4061 /* unknown_2 6 NULL bytes follow*/
4063 /* now set the quotas */
4064 if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
4065 DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), SNUM(conn))));
4066 reply_nterror(req, map_nt_error_from_unix(errno));
4067 return;
4070 break;
4072 default:
4073 DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
4074 info_level));
4075 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4076 return;
4077 break;
4081 * sending this reply works fine,
4082 * but I'm not sure it's the same
4083 * like windows do...
4084 * --metze
4086 reply_outbuf(req, 10, 0);
4089 #if defined(HAVE_POSIX_ACLS)
4090 /****************************************************************************
4091 Utility function to count the number of entries in a POSIX acl.
4092 ****************************************************************************/
4094 static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
4096 unsigned int ace_count = 0;
4097 int entry_id = SMB_ACL_FIRST_ENTRY;
4098 SMB_ACL_ENTRY_T entry;
4100 while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
4101 /* get_next... */
4102 if (entry_id == SMB_ACL_FIRST_ENTRY) {
4103 entry_id = SMB_ACL_NEXT_ENTRY;
4105 ace_count++;
4107 return ace_count;
4110 /****************************************************************************
4111 Utility function to marshall a POSIX acl into wire format.
4112 ****************************************************************************/
4114 static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
4116 int entry_id = SMB_ACL_FIRST_ENTRY;
4117 SMB_ACL_ENTRY_T entry;
4119 while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
4120 SMB_ACL_TAG_T tagtype;
4121 SMB_ACL_PERMSET_T permset;
4122 unsigned char perms = 0;
4123 unsigned int own_grp;
4125 /* get_next... */
4126 if (entry_id == SMB_ACL_FIRST_ENTRY) {
4127 entry_id = SMB_ACL_NEXT_ENTRY;
4130 if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
4131 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
4132 return False;
4135 if (sys_acl_get_permset(entry, &permset) == -1) {
4136 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
4137 return False;
4140 perms |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
4141 perms |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
4142 perms |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
4144 SCVAL(pdata,1,perms);
4146 switch (tagtype) {
4147 case SMB_ACL_USER_OBJ:
4148 SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
4149 own_grp = (unsigned int)pst->st_ex_uid;
4150 SIVAL(pdata,2,own_grp);
4151 SIVAL(pdata,6,0);
4152 break;
4153 case SMB_ACL_USER:
4155 uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
4156 if (!puid) {
4157 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
4158 return False;
4160 own_grp = (unsigned int)*puid;
4161 SCVAL(pdata,0,SMB_POSIX_ACL_USER);
4162 SIVAL(pdata,2,own_grp);
4163 SIVAL(pdata,6,0);
4164 break;
4166 case SMB_ACL_GROUP_OBJ:
4167 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
4168 own_grp = (unsigned int)pst->st_ex_gid;
4169 SIVAL(pdata,2,own_grp);
4170 SIVAL(pdata,6,0);
4171 break;
4172 case SMB_ACL_GROUP:
4174 gid_t *pgid= (gid_t *)sys_acl_get_qualifier(entry);
4175 if (!pgid) {
4176 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
4177 return False;
4179 own_grp = (unsigned int)*pgid;
4180 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
4181 SIVAL(pdata,2,own_grp);
4182 SIVAL(pdata,6,0);
4183 break;
4185 case SMB_ACL_MASK:
4186 SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
4187 SIVAL(pdata,2,0xFFFFFFFF);
4188 SIVAL(pdata,6,0xFFFFFFFF);
4189 break;
4190 case SMB_ACL_OTHER:
4191 SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
4192 SIVAL(pdata,2,0xFFFFFFFF);
4193 SIVAL(pdata,6,0xFFFFFFFF);
4194 break;
4195 default:
4196 DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
4197 return False;
4199 pdata += SMB_POSIX_ACL_ENTRY_SIZE;
4202 return True;
4204 #endif
4206 /****************************************************************************
4207 Store the FILE_UNIX_BASIC info.
4208 ****************************************************************************/
4210 static char *store_file_unix_basic(connection_struct *conn,
4211 char *pdata,
4212 files_struct *fsp,
4213 const SMB_STRUCT_STAT *psbuf)
4215 uint64_t file_index = get_FileIndex(conn, psbuf);
4216 dev_t devno;
4218 DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
4219 DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode));
4221 SOFF_T(pdata,0,get_file_size_stat(psbuf)); /* File size 64 Bit */
4222 pdata += 8;
4224 SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
4225 pdata += 8;
4227 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, psbuf->st_ex_ctime); /* Change Time 64 Bit */
4228 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, psbuf->st_ex_atime); /* Last access time 64 Bit */
4229 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, psbuf->st_ex_mtime); /* Last modification time 64 Bit */
4230 pdata += 24;
4232 SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */
4233 SIVAL(pdata,4,0);
4234 pdata += 8;
4236 SIVAL(pdata,0,psbuf->st_ex_gid); /* group id of owner */
4237 SIVAL(pdata,4,0);
4238 pdata += 8;
4240 SIVAL(pdata,0,unix_filetype(psbuf->st_ex_mode));
4241 pdata += 4;
4243 if (S_ISBLK(psbuf->st_ex_mode) || S_ISCHR(psbuf->st_ex_mode)) {
4244 devno = psbuf->st_ex_rdev;
4245 } else {
4246 devno = psbuf->st_ex_dev;
4249 SIVAL(pdata,0,unix_dev_major(devno)); /* Major device number if type is device */
4250 SIVAL(pdata,4,0);
4251 pdata += 8;
4253 SIVAL(pdata,0,unix_dev_minor(devno)); /* Minor device number if type is device */
4254 SIVAL(pdata,4,0);
4255 pdata += 8;
4257 SINO_T_VAL(pdata,0,(SMB_INO_T)file_index); /* inode number */
4258 pdata += 8;
4260 SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode)); /* Standard UNIX file permissions */
4261 SIVAL(pdata,4,0);
4262 pdata += 8;
4264 SIVAL(pdata,0,psbuf->st_ex_nlink); /* number of hard links */
4265 SIVAL(pdata,4,0);
4266 pdata += 8;
4268 return pdata;
4271 /* Forward and reverse mappings from the UNIX_INFO2 file flags field and
4272 * the chflags(2) (or equivalent) flags.
4274 * XXX: this really should be behind the VFS interface. To do this, we would
4275 * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field.
4276 * Each VFS module could then implement its own mapping as appropriate for the
4277 * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS.
4279 static const struct {unsigned stat_fflag; unsigned smb_fflag;}
4280 info2_flags_map[] =
4282 #ifdef UF_NODUMP
4283 { UF_NODUMP, EXT_DO_NOT_BACKUP },
4284 #endif
4286 #ifdef UF_IMMUTABLE
4287 { UF_IMMUTABLE, EXT_IMMUTABLE },
4288 #endif
4290 #ifdef UF_APPEND
4291 { UF_APPEND, EXT_OPEN_APPEND_ONLY },
4292 #endif
4294 #ifdef UF_HIDDEN
4295 { UF_HIDDEN, EXT_HIDDEN },
4296 #endif
4298 /* Do not remove. We need to guarantee that this array has at least one
4299 * entry to build on HP-UX.
4301 { 0, 0 }
4305 static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
4306 uint32 *smb_fflags, uint32 *smb_fmask)
4308 int i;
4310 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
4311 *smb_fmask |= info2_flags_map[i].smb_fflag;
4312 if (psbuf->st_ex_flags & info2_flags_map[i].stat_fflag) {
4313 *smb_fflags |= info2_flags_map[i].smb_fflag;
4318 static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
4319 const uint32 smb_fflags,
4320 const uint32 smb_fmask,
4321 int *stat_fflags)
4323 uint32 max_fmask = 0;
4324 int i;
4326 *stat_fflags = psbuf->st_ex_flags;
4328 /* For each flags requested in smb_fmask, check the state of the
4329 * corresponding flag in smb_fflags and set or clear the matching
4330 * stat flag.
4333 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
4334 max_fmask |= info2_flags_map[i].smb_fflag;
4335 if (smb_fmask & info2_flags_map[i].smb_fflag) {
4336 if (smb_fflags & info2_flags_map[i].smb_fflag) {
4337 *stat_fflags |= info2_flags_map[i].stat_fflag;
4338 } else {
4339 *stat_fflags &= ~info2_flags_map[i].stat_fflag;
4344 /* If smb_fmask is asking to set any bits that are not supported by
4345 * our flag mappings, we should fail.
4347 if ((smb_fmask & max_fmask) != smb_fmask) {
4348 return False;
4351 return True;
4355 /* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition
4356 * of file flags and birth (create) time.
4358 static char *store_file_unix_basic_info2(connection_struct *conn,
4359 char *pdata,
4360 files_struct *fsp,
4361 const SMB_STRUCT_STAT *psbuf)
4363 uint32 file_flags = 0;
4364 uint32 flags_mask = 0;
4366 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
4368 /* Create (birth) time 64 bit */
4369 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, psbuf->st_ex_btime);
4370 pdata += 8;
4372 map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
4373 SIVAL(pdata, 0, file_flags); /* flags */
4374 SIVAL(pdata, 4, flags_mask); /* mask */
4375 pdata += 8;
4377 return pdata;
4380 static NTSTATUS marshall_stream_info(unsigned int num_streams,
4381 const struct stream_struct *streams,
4382 char *data,
4383 unsigned int max_data_bytes,
4384 unsigned int *data_size)
4386 unsigned int i;
4387 unsigned int ofs = 0;
4389 if (max_data_bytes < 32) {
4390 return NT_STATUS_INFO_LENGTH_MISMATCH;
4393 for (i = 0; i < num_streams; i++) {
4394 unsigned int next_offset;
4395 size_t namelen;
4396 smb_ucs2_t *namebuf;
4398 if (!push_ucs2_talloc(talloc_tos(), &namebuf,
4399 streams[i].name, &namelen) ||
4400 namelen <= 2)
4402 return NT_STATUS_INVALID_PARAMETER;
4406 * name_buf is now null-terminated, we need to marshall as not
4407 * terminated
4410 namelen -= 2;
4413 * We cannot overflow ...
4415 if ((ofs + 24 + namelen) > max_data_bytes) {
4416 DEBUG(10, ("refusing to overflow reply at stream %u\n",
4417 i));
4418 TALLOC_FREE(namebuf);
4419 return STATUS_BUFFER_OVERFLOW;
4422 SIVAL(data, ofs+4, namelen);
4423 SOFF_T(data, ofs+8, streams[i].size);
4424 SOFF_T(data, ofs+16, streams[i].alloc_size);
4425 memcpy(data+ofs+24, namebuf, namelen);
4426 TALLOC_FREE(namebuf);
4428 next_offset = ofs + 24 + namelen;
4430 if (i == num_streams-1) {
4431 SIVAL(data, ofs, 0);
4433 else {
4434 unsigned int align = ndr_align_size(next_offset, 8);
4436 if ((next_offset + align) > max_data_bytes) {
4437 DEBUG(10, ("refusing to overflow align "
4438 "reply at stream %u\n",
4439 i));
4440 TALLOC_FREE(namebuf);
4441 return STATUS_BUFFER_OVERFLOW;
4444 memset(data+next_offset, 0, align);
4445 next_offset += align;
4447 SIVAL(data, ofs, next_offset - ofs);
4448 ofs = next_offset;
4451 ofs = next_offset;
4454 DEBUG(10, ("max_data: %u, data_size: %u\n", max_data_bytes, ofs));
4456 *data_size = ofs;
4458 return NT_STATUS_OK;
4461 /****************************************************************************
4462 Reply to a TRANSACT2_QFILEINFO on a PIPE !
4463 ****************************************************************************/
4465 static void call_trans2qpipeinfo(connection_struct *conn,
4466 struct smb_request *req,
4467 unsigned int tran_call,
4468 char **pparams, int total_params,
4469 char **ppdata, int total_data,
4470 unsigned int max_data_bytes)
4472 char *params = *pparams;
4473 char *pdata = *ppdata;
4474 unsigned int data_size = 0;
4475 unsigned int param_size = 2;
4476 uint16 info_level;
4477 files_struct *fsp;
4479 if (!params) {
4480 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4481 return;
4484 if (total_params < 4) {
4485 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4486 return;
4489 fsp = file_fsp(req, SVAL(params,0));
4490 if (!fsp_is_np(fsp)) {
4491 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4492 return;
4495 info_level = SVAL(params,2);
4497 *pparams = (char *)SMB_REALLOC(*pparams,2);
4498 if (*pparams == NULL) {
4499 reply_nterror(req, NT_STATUS_NO_MEMORY);
4500 return;
4502 params = *pparams;
4503 SSVAL(params,0,0);
4504 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
4505 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4506 return;
4508 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
4509 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
4510 if (*ppdata == NULL ) {
4511 reply_nterror(req, NT_STATUS_NO_MEMORY);
4512 return;
4514 pdata = *ppdata;
4516 switch (info_level) {
4517 case SMB_FILE_STANDARD_INFORMATION:
4518 memset(pdata,0,24);
4519 SOFF_T(pdata,0,4096LL);
4520 SIVAL(pdata,16,1);
4521 SIVAL(pdata,20,1);
4522 data_size = 24;
4523 break;
4525 default:
4526 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4527 return;
4530 send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
4531 max_data_bytes);
4533 return;
4536 NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
4537 TALLOC_CTX *mem_ctx,
4538 uint16_t info_level,
4539 files_struct *fsp,
4540 struct smb_filename *smb_fname,
4541 bool delete_pending,
4542 struct timespec write_time_ts,
4543 struct ea_list *ea_list,
4544 int lock_data_count,
4545 char *lock_data,
4546 uint16_t flags2,
4547 unsigned int max_data_bytes,
4548 size_t *fixed_portion,
4549 char **ppdata,
4550 unsigned int *pdata_size)
4552 char *pdata = *ppdata;
4553 char *dstart, *dend;
4554 unsigned int data_size;
4555 struct timespec create_time_ts, mtime_ts, atime_ts, ctime_ts;
4556 time_t create_time, mtime, atime, c_time;
4557 SMB_STRUCT_STAT *psbuf = &smb_fname->st;
4558 char *p;
4559 char *base_name;
4560 char *dos_fname;
4561 int mode;
4562 int nlink;
4563 NTSTATUS status;
4564 uint64_t file_size = 0;
4565 uint64_t pos = 0;
4566 uint64_t allocation_size = 0;
4567 uint64_t file_index = 0;
4568 uint32_t access_mask = 0;
4569 size_t len = 0;
4571 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
4572 return NT_STATUS_INVALID_LEVEL;
4575 DEBUG(5,("smbd_do_qfilepathinfo: %s (%s) level=%d max_data=%u\n",
4576 smb_fname_str_dbg(smb_fname),
4577 fsp_fnum_dbg(fsp),
4578 info_level, max_data_bytes));
4580 mode = dos_mode(conn, smb_fname);
4581 nlink = psbuf->st_ex_nlink;
4583 if (nlink && (mode&FILE_ATTRIBUTE_DIRECTORY)) {
4584 nlink = 1;
4587 if ((nlink > 0) && delete_pending) {
4588 nlink -= 1;
4591 if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
4592 return NT_STATUS_INVALID_PARAMETER;
4595 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
4596 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
4597 if (*ppdata == NULL) {
4598 return NT_STATUS_NO_MEMORY;
4600 pdata = *ppdata;
4601 dstart = pdata;
4602 dend = dstart + data_size - 1;
4604 if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) {
4605 update_stat_ex_mtime(psbuf, write_time_ts);
4608 create_time_ts = get_create_timespec(conn, fsp, smb_fname);
4609 mtime_ts = psbuf->st_ex_mtime;
4610 atime_ts = psbuf->st_ex_atime;
4611 ctime_ts = get_change_timespec(conn, fsp, smb_fname);
4613 if (lp_dos_filetime_resolution(SNUM(conn))) {
4614 dos_filetime_timespec(&create_time_ts);
4615 dos_filetime_timespec(&mtime_ts);
4616 dos_filetime_timespec(&atime_ts);
4617 dos_filetime_timespec(&ctime_ts);
4620 create_time = convert_timespec_to_time_t(create_time_ts);
4621 mtime = convert_timespec_to_time_t(mtime_ts);
4622 atime = convert_timespec_to_time_t(atime_ts);
4623 c_time = convert_timespec_to_time_t(ctime_ts);
4625 p = strrchr_m(smb_fname->base_name,'/');
4626 if (!p)
4627 base_name = smb_fname->base_name;
4628 else
4629 base_name = p+1;
4631 /* NT expects the name to be in an exact form of the *full*
4632 filename. See the trans2 torture test */
4633 if (ISDOT(base_name)) {
4634 dos_fname = talloc_strdup(mem_ctx, "\\");
4635 if (!dos_fname) {
4636 return NT_STATUS_NO_MEMORY;
4638 } else {
4639 dos_fname = talloc_asprintf(mem_ctx,
4640 "\\%s",
4641 smb_fname->base_name);
4642 if (!dos_fname) {
4643 return NT_STATUS_NO_MEMORY;
4645 if (is_ntfs_stream_smb_fname(smb_fname)) {
4646 dos_fname = talloc_asprintf(dos_fname, "%s",
4647 smb_fname->stream_name);
4648 if (!dos_fname) {
4649 return NT_STATUS_NO_MEMORY;
4653 string_replace(dos_fname, '/', '\\');
4656 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, psbuf);
4658 if (!fsp) {
4659 /* Do we have this path open ? */
4660 files_struct *fsp1;
4661 struct file_id fileid = vfs_file_id_from_sbuf(conn, psbuf);
4662 fsp1 = file_find_di_first(conn->sconn, fileid);
4663 if (fsp1 && fsp1->initial_allocation_size) {
4664 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, psbuf);
4668 if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) {
4669 file_size = get_file_size_stat(psbuf);
4672 if (fsp) {
4673 pos = fsp->fh->position_information;
4676 if (fsp) {
4677 access_mask = fsp->access_mask;
4678 } else {
4679 /* GENERIC_EXECUTE mapping from Windows */
4680 access_mask = 0x12019F;
4683 /* This should be an index number - looks like
4684 dev/ino to me :-)
4686 I think this causes us to fail the IFSKIT
4687 BasicFileInformationTest. -tpot */
4688 file_index = get_FileIndex(conn, psbuf);
4690 *fixed_portion = 0;
4692 switch (info_level) {
4693 case SMB_INFO_STANDARD:
4694 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
4695 data_size = 22;
4696 srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
4697 srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
4698 srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
4699 SIVAL(pdata,l1_cbFile,(uint32)file_size);
4700 SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
4701 SSVAL(pdata,l1_attrFile,mode);
4702 break;
4704 case SMB_INFO_QUERY_EA_SIZE:
4706 unsigned int ea_size =
4707 estimate_ea_size(conn, fsp,
4708 smb_fname);
4709 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
4710 data_size = 26;
4711 srv_put_dos_date2(pdata,0,create_time);
4712 srv_put_dos_date2(pdata,4,atime);
4713 srv_put_dos_date2(pdata,8,mtime); /* write time */
4714 SIVAL(pdata,12,(uint32)file_size);
4715 SIVAL(pdata,16,(uint32)allocation_size);
4716 SSVAL(pdata,20,mode);
4717 SIVAL(pdata,22,ea_size);
4718 break;
4721 case SMB_INFO_IS_NAME_VALID:
4722 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
4723 if (fsp) {
4724 /* os/2 needs this ? really ?*/
4725 return NT_STATUS_DOS(ERRDOS, ERRbadfunc);
4727 /* This is only reached for qpathinfo */
4728 data_size = 0;
4729 break;
4731 case SMB_INFO_QUERY_EAS_FROM_LIST:
4733 size_t total_ea_len = 0;
4734 struct ea_list *ea_file_list = NULL;
4735 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
4737 status =
4738 get_ea_list_from_file(mem_ctx, conn, fsp,
4739 smb_fname,
4740 &total_ea_len, &ea_file_list);
4741 if (!NT_STATUS_IS_OK(status)) {
4742 return status;
4745 ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
4747 if (!ea_list || (total_ea_len > data_size)) {
4748 data_size = 4;
4749 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
4750 break;
4753 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
4754 break;
4757 case SMB_INFO_QUERY_ALL_EAS:
4759 /* We have data_size bytes to put EA's into. */
4760 size_t total_ea_len = 0;
4761 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
4763 status = get_ea_list_from_file(mem_ctx, conn, fsp,
4764 smb_fname,
4765 &total_ea_len, &ea_list);
4766 if (!NT_STATUS_IS_OK(status)) {
4767 return status;
4770 if (!ea_list || (total_ea_len > data_size)) {
4771 data_size = 4;
4772 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
4773 break;
4776 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
4777 break;
4780 case 0xFF0F:/*SMB2_INFO_QUERY_ALL_EAS*/
4782 /* This is FileFullEaInformation - 0xF which maps to
4783 * 1015 (decimal) in smbd_do_setfilepathinfo. */
4785 /* We have data_size bytes to put EA's into. */
4786 size_t total_ea_len = 0;
4787 struct ea_list *ea_file_list = NULL;
4789 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n"));
4791 /*TODO: add filtering and index handling */
4793 status =
4794 get_ea_list_from_file(mem_ctx, conn, fsp,
4795 smb_fname,
4796 &total_ea_len, &ea_file_list);
4797 if (!NT_STATUS_IS_OK(status)) {
4798 return status;
4800 if (!ea_file_list) {
4801 return NT_STATUS_NO_EAS_ON_FILE;
4804 status = fill_ea_chained_buffer(mem_ctx,
4805 pdata,
4806 data_size,
4807 &data_size,
4808 conn, ea_file_list);
4809 if (!NT_STATUS_IS_OK(status)) {
4810 return status;
4812 break;
4815 case SMB_FILE_BASIC_INFORMATION:
4816 case SMB_QUERY_FILE_BASIC_INFO:
4818 if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
4819 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
4820 data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
4821 } else {
4822 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
4823 data_size = 40;
4824 SIVAL(pdata,36,0);
4826 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
4827 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
4828 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
4829 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
4830 SIVAL(pdata,32,mode);
4832 DEBUG(5,("SMB_QFBI - "));
4833 DEBUG(5,("create: %s ", ctime(&create_time)));
4834 DEBUG(5,("access: %s ", ctime(&atime)));
4835 DEBUG(5,("write: %s ", ctime(&mtime)));
4836 DEBUG(5,("change: %s ", ctime(&c_time)));
4837 DEBUG(5,("mode: %x\n", mode));
4838 *fixed_portion = data_size;
4839 break;
4841 case SMB_FILE_STANDARD_INFORMATION:
4842 case SMB_QUERY_FILE_STANDARD_INFO:
4844 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
4845 data_size = 24;
4846 SOFF_T(pdata,0,allocation_size);
4847 SOFF_T(pdata,8,file_size);
4848 SIVAL(pdata,16,nlink);
4849 SCVAL(pdata,20,delete_pending?1:0);
4850 SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
4851 SSVAL(pdata,22,0); /* Padding. */
4852 *fixed_portion = 24;
4853 break;
4855 case SMB_FILE_EA_INFORMATION:
4856 case SMB_QUERY_FILE_EA_INFO:
4858 unsigned int ea_size =
4859 estimate_ea_size(conn, fsp, smb_fname);
4860 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
4861 data_size = 4;
4862 *fixed_portion = 4;
4863 SIVAL(pdata,0,ea_size);
4864 break;
4867 /* Get the 8.3 name - used if NT SMB was negotiated. */
4868 case SMB_QUERY_FILE_ALT_NAME_INFO:
4869 case SMB_FILE_ALTERNATE_NAME_INFORMATION:
4871 char mangled_name[13];
4872 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
4873 if (!name_to_8_3(base_name,mangled_name,
4874 True,conn->params)) {
4875 return NT_STATUS_NO_MEMORY;
4877 status = srvstr_push(dstart, flags2,
4878 pdata+4, mangled_name,
4879 PTR_DIFF(dend, pdata+4),
4880 STR_UNICODE, &len);
4881 if (!NT_STATUS_IS_OK(status)) {
4882 return status;
4884 data_size = 4 + len;
4885 SIVAL(pdata,0,len);
4886 *fixed_portion = 8;
4887 break;
4890 case SMB_QUERY_FILE_NAME_INFO:
4893 this must be *exactly* right for ACLs on mapped drives to work
4895 status = srvstr_push(dstart, flags2,
4896 pdata+4, dos_fname,
4897 PTR_DIFF(dend, pdata+4),
4898 STR_UNICODE, &len);
4899 if (!NT_STATUS_IS_OK(status)) {
4900 return status;
4902 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
4903 data_size = 4 + len;
4904 SIVAL(pdata,0,len);
4905 break;
4908 case SMB_FILE_ALLOCATION_INFORMATION:
4909 case SMB_QUERY_FILE_ALLOCATION_INFO:
4910 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
4911 data_size = 8;
4912 SOFF_T(pdata,0,allocation_size);
4913 break;
4915 case SMB_FILE_END_OF_FILE_INFORMATION:
4916 case SMB_QUERY_FILE_END_OF_FILEINFO:
4917 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
4918 data_size = 8;
4919 SOFF_T(pdata,0,file_size);
4920 break;
4922 case SMB_QUERY_FILE_ALL_INFO:
4923 case SMB_FILE_ALL_INFORMATION:
4925 unsigned int ea_size =
4926 estimate_ea_size(conn, fsp, smb_fname);
4927 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
4928 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
4929 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
4930 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
4931 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
4932 SIVAL(pdata,32,mode);
4933 SIVAL(pdata,36,0); /* padding. */
4934 pdata += 40;
4935 SOFF_T(pdata,0,allocation_size);
4936 SOFF_T(pdata,8,file_size);
4937 SIVAL(pdata,16,nlink);
4938 SCVAL(pdata,20,delete_pending);
4939 SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
4940 SSVAL(pdata,22,0);
4941 pdata += 24;
4942 SIVAL(pdata,0,ea_size);
4943 pdata += 4; /* EA info */
4944 status = srvstr_push(dstart, flags2,
4945 pdata+4, dos_fname,
4946 PTR_DIFF(dend, pdata+4),
4947 STR_UNICODE, &len);
4948 if (!NT_STATUS_IS_OK(status)) {
4949 return status;
4951 SIVAL(pdata,0,len);
4952 pdata += 4 + len;
4953 data_size = PTR_DIFF(pdata,(*ppdata));
4954 *fixed_portion = 10;
4955 break;
4958 case 0xFF12:/*SMB2_FILE_ALL_INFORMATION*/
4960 unsigned int ea_size =
4961 estimate_ea_size(conn, fsp, smb_fname);
4962 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
4963 put_long_date_timespec(conn->ts_res,pdata+0x00,create_time_ts);
4964 put_long_date_timespec(conn->ts_res,pdata+0x08,atime_ts);
4965 put_long_date_timespec(conn->ts_res,pdata+0x10,mtime_ts); /* write time */
4966 put_long_date_timespec(conn->ts_res,pdata+0x18,ctime_ts); /* change time */
4967 SIVAL(pdata, 0x20, mode);
4968 SIVAL(pdata, 0x24, 0); /* padding. */
4969 SBVAL(pdata, 0x28, allocation_size);
4970 SBVAL(pdata, 0x30, file_size);
4971 SIVAL(pdata, 0x38, nlink);
4972 SCVAL(pdata, 0x3C, delete_pending);
4973 SCVAL(pdata, 0x3D, (mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
4974 SSVAL(pdata, 0x3E, 0); /* padding */
4975 SBVAL(pdata, 0x40, file_index);
4976 SIVAL(pdata, 0x48, ea_size);
4977 SIVAL(pdata, 0x4C, access_mask);
4978 SBVAL(pdata, 0x50, pos);
4979 SIVAL(pdata, 0x58, mode); /*TODO: mode != mode fix this!!! */
4980 SIVAL(pdata, 0x5C, 0); /* No alignment needed. */
4982 pdata += 0x60;
4984 status = srvstr_push(dstart, flags2,
4985 pdata+4, dos_fname,
4986 PTR_DIFF(dend, pdata+4),
4987 STR_UNICODE, &len);
4988 if (!NT_STATUS_IS_OK(status)) {
4989 return status;
4991 SIVAL(pdata,0,len);
4992 pdata += 4 + len;
4993 data_size = PTR_DIFF(pdata,(*ppdata));
4994 *fixed_portion = 104;
4995 break;
4997 case SMB_FILE_INTERNAL_INFORMATION:
4999 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
5000 SBVAL(pdata, 0, file_index);
5001 data_size = 8;
5002 *fixed_portion = 8;
5003 break;
5005 case SMB_FILE_ACCESS_INFORMATION:
5006 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
5007 SIVAL(pdata, 0, access_mask);
5008 data_size = 4;
5009 *fixed_portion = 4;
5010 break;
5012 case SMB_FILE_NAME_INFORMATION:
5013 /* Pathname with leading '\'. */
5015 size_t byte_len;
5016 byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
5017 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
5018 SIVAL(pdata,0,byte_len);
5019 data_size = 4 + byte_len;
5020 break;
5023 case SMB_FILE_DISPOSITION_INFORMATION:
5024 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
5025 data_size = 1;
5026 SCVAL(pdata,0,delete_pending);
5027 *fixed_portion = 1;
5028 break;
5030 case SMB_FILE_POSITION_INFORMATION:
5031 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
5032 data_size = 8;
5033 SOFF_T(pdata,0,pos);
5034 *fixed_portion = 8;
5035 break;
5037 case SMB_FILE_MODE_INFORMATION:
5038 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
5039 SIVAL(pdata,0,mode);
5040 data_size = 4;
5041 *fixed_portion = 4;
5042 break;
5044 case SMB_FILE_ALIGNMENT_INFORMATION:
5045 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
5046 SIVAL(pdata,0,0); /* No alignment needed. */
5047 data_size = 4;
5048 *fixed_portion = 4;
5049 break;
5052 * NT4 server just returns "invalid query" to this - if we try
5053 * to answer it then NTws gets a BSOD! (tridge). W2K seems to
5054 * want this. JRA.
5056 /* The first statement above is false - verified using Thursby
5057 * client against NT4 -- gcolley.
5059 case SMB_QUERY_FILE_STREAM_INFO:
5060 case SMB_FILE_STREAM_INFORMATION: {
5061 unsigned int num_streams = 0;
5062 struct stream_struct *streams = NULL;
5064 DEBUG(10,("smbd_do_qfilepathinfo: "
5065 "SMB_FILE_STREAM_INFORMATION\n"));
5067 if (is_ntfs_stream_smb_fname(smb_fname)) {
5068 return NT_STATUS_INVALID_PARAMETER;
5071 status = vfs_streaminfo(conn, fsp, smb_fname->base_name,
5072 talloc_tos(), &num_streams, &streams);
5074 if (!NT_STATUS_IS_OK(status)) {
5075 DEBUG(10, ("could not get stream info: %s\n",
5076 nt_errstr(status)));
5077 return status;
5080 status = marshall_stream_info(num_streams, streams,
5081 pdata, max_data_bytes,
5082 &data_size);
5084 if (!NT_STATUS_IS_OK(status)) {
5085 DEBUG(10, ("marshall_stream_info failed: %s\n",
5086 nt_errstr(status)));
5087 TALLOC_FREE(streams);
5088 return status;
5091 TALLOC_FREE(streams);
5093 *fixed_portion = 32;
5095 break;
5097 case SMB_QUERY_COMPRESSION_INFO:
5098 case SMB_FILE_COMPRESSION_INFORMATION:
5099 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
5100 SOFF_T(pdata,0,file_size);
5101 SIVAL(pdata,8,0); /* ??? */
5102 SIVAL(pdata,12,0); /* ??? */
5103 data_size = 16;
5104 *fixed_portion = 16;
5105 break;
5107 case SMB_FILE_NETWORK_OPEN_INFORMATION:
5108 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
5109 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
5110 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
5111 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
5112 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
5113 SOFF_T(pdata,32,allocation_size);
5114 SOFF_T(pdata,40,file_size);
5115 SIVAL(pdata,48,mode);
5116 SIVAL(pdata,52,0); /* ??? */
5117 data_size = 56;
5118 *fixed_portion = 56;
5119 break;
5121 case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
5122 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
5123 SIVAL(pdata,0,mode);
5124 SIVAL(pdata,4,0);
5125 data_size = 8;
5126 *fixed_portion = 8;
5127 break;
5130 * CIFS UNIX Extensions.
5133 case SMB_QUERY_FILE_UNIX_BASIC:
5135 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
5136 data_size = PTR_DIFF(pdata,(*ppdata));
5138 DEBUG(4,("smbd_do_qfilepathinfo: "
5139 "SMB_QUERY_FILE_UNIX_BASIC\n"));
5140 dump_data(4, (uint8_t *)(*ppdata), data_size);
5142 break;
5144 case SMB_QUERY_FILE_UNIX_INFO2:
5146 pdata = store_file_unix_basic_info2(conn, pdata, fsp, psbuf);
5147 data_size = PTR_DIFF(pdata,(*ppdata));
5150 int i;
5151 DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));
5153 for (i=0; i<100; i++)
5154 DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
5155 DEBUG(4,("\n"));
5158 break;
5160 case SMB_QUERY_FILE_UNIX_LINK:
5162 int link_len = 0;
5163 char *buffer = talloc_array(mem_ctx, char, PATH_MAX+1);
5165 if (!buffer) {
5166 return NT_STATUS_NO_MEMORY;
5169 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n"));
5170 #ifdef S_ISLNK
5171 if(!S_ISLNK(psbuf->st_ex_mode)) {
5172 return NT_STATUS_DOS(ERRSRV, ERRbadlink);
5174 #else
5175 return NT_STATUS_DOS(ERRDOS, ERRbadlink);
5176 #endif
5177 link_len = SMB_VFS_READLINK(conn,
5178 smb_fname->base_name,
5179 buffer, PATH_MAX);
5180 if (link_len == -1) {
5181 return map_nt_error_from_unix(errno);
5183 buffer[link_len] = 0;
5184 status = srvstr_push(dstart, flags2,
5185 pdata, buffer,
5186 PTR_DIFF(dend, pdata),
5187 STR_TERMINATE, &len);
5188 if (!NT_STATUS_IS_OK(status)) {
5189 return status;
5191 pdata += len;
5192 data_size = PTR_DIFF(pdata,(*ppdata));
5194 break;
5197 #if defined(HAVE_POSIX_ACLS)
5198 case SMB_QUERY_POSIX_ACL:
5200 SMB_ACL_T file_acl = NULL;
5201 SMB_ACL_T def_acl = NULL;
5202 uint16 num_file_acls = 0;
5203 uint16 num_def_acls = 0;
5205 if (fsp && fsp->fh->fd != -1) {
5206 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
5207 talloc_tos());
5208 } else {
5209 file_acl =
5210 SMB_VFS_SYS_ACL_GET_FILE(conn,
5211 smb_fname->base_name,
5212 SMB_ACL_TYPE_ACCESS,
5213 talloc_tos());
5216 if (file_acl == NULL && no_acl_syscall_error(errno)) {
5217 DEBUG(5,("smbd_do_qfilepathinfo: ACLs "
5218 "not implemented on "
5219 "filesystem containing %s\n",
5220 smb_fname->base_name));
5221 return NT_STATUS_NOT_IMPLEMENTED;
5224 if (S_ISDIR(psbuf->st_ex_mode)) {
5225 if (fsp && fsp->is_directory) {
5226 def_acl =
5227 SMB_VFS_SYS_ACL_GET_FILE(
5228 conn,
5229 fsp->fsp_name->base_name,
5230 SMB_ACL_TYPE_DEFAULT,
5231 talloc_tos());
5232 } else {
5233 def_acl =
5234 SMB_VFS_SYS_ACL_GET_FILE(
5235 conn,
5236 smb_fname->base_name,
5237 SMB_ACL_TYPE_DEFAULT,
5238 talloc_tos());
5240 def_acl = free_empty_sys_acl(conn, def_acl);
5243 num_file_acls = count_acl_entries(conn, file_acl);
5244 num_def_acls = count_acl_entries(conn, def_acl);
5246 if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) {
5247 DEBUG(5,("smbd_do_qfilepathinfo: data_size too small (%u) need %u\n",
5248 data_size,
5249 (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
5250 SMB_POSIX_ACL_HEADER_SIZE) ));
5251 if (file_acl) {
5252 TALLOC_FREE(file_acl);
5254 if (def_acl) {
5255 TALLOC_FREE(def_acl);
5257 return NT_STATUS_BUFFER_TOO_SMALL;
5260 SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
5261 SSVAL(pdata,2,num_file_acls);
5262 SSVAL(pdata,4,num_def_acls);
5263 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, psbuf, file_acl)) {
5264 if (file_acl) {
5265 TALLOC_FREE(file_acl);
5267 if (def_acl) {
5268 TALLOC_FREE(def_acl);
5270 return NT_STATUS_INTERNAL_ERROR;
5272 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), psbuf, def_acl)) {
5273 if (file_acl) {
5274 TALLOC_FREE(file_acl);
5276 if (def_acl) {
5277 TALLOC_FREE(def_acl);
5279 return NT_STATUS_INTERNAL_ERROR;
5282 if (file_acl) {
5283 TALLOC_FREE(file_acl);
5285 if (def_acl) {
5286 TALLOC_FREE(def_acl);
5288 data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
5289 break;
5291 #endif
5294 case SMB_QUERY_POSIX_LOCK:
5296 uint64_t count;
5297 uint64_t offset;
5298 uint64_t smblctx;
5299 enum brl_type lock_type;
5301 /* We need an open file with a real fd for this. */
5302 if (!fsp || fsp->fh->fd == -1) {
5303 return NT_STATUS_INVALID_LEVEL;
5306 if (lock_data_count != POSIX_LOCK_DATA_SIZE) {
5307 return NT_STATUS_INVALID_PARAMETER;
5310 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
5311 case POSIX_LOCK_TYPE_READ:
5312 lock_type = READ_LOCK;
5313 break;
5314 case POSIX_LOCK_TYPE_WRITE:
5315 lock_type = WRITE_LOCK;
5316 break;
5317 case POSIX_LOCK_TYPE_UNLOCK:
5318 default:
5319 /* There's no point in asking for an unlock... */
5320 return NT_STATUS_INVALID_PARAMETER;
5323 smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
5324 offset = BVAL(pdata,POSIX_LOCK_START_OFFSET);
5325 count = BVAL(pdata,POSIX_LOCK_LEN_OFFSET);
5327 status = query_lock(fsp,
5328 &smblctx,
5329 &count,
5330 &offset,
5331 &lock_type,
5332 POSIX_LOCK);
5334 if (ERROR_WAS_LOCK_DENIED(status)) {
5335 /* Here we need to report who has it locked... */
5336 data_size = POSIX_LOCK_DATA_SIZE;
5338 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
5339 SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
5340 SIVAL(pdata, POSIX_LOCK_PID_OFFSET, (uint32_t)smblctx);
5341 SBVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
5342 SBVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
5344 } else if (NT_STATUS_IS_OK(status)) {
5345 /* For success we just return a copy of what we sent
5346 with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
5347 data_size = POSIX_LOCK_DATA_SIZE;
5348 memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
5349 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
5350 } else {
5351 return status;
5353 break;
5356 default:
5357 return NT_STATUS_INVALID_LEVEL;
5360 *pdata_size = data_size;
5361 return NT_STATUS_OK;
5364 /****************************************************************************
5365 Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
5366 file name or file id).
5367 ****************************************************************************/
5369 static void call_trans2qfilepathinfo(connection_struct *conn,
5370 struct smb_request *req,
5371 unsigned int tran_call,
5372 char **pparams, int total_params,
5373 char **ppdata, int total_data,
5374 unsigned int max_data_bytes)
5376 char *params = *pparams;
5377 char *pdata = *ppdata;
5378 uint16 info_level;
5379 unsigned int data_size = 0;
5380 unsigned int param_size = 2;
5381 struct smb_filename *smb_fname = NULL;
5382 bool delete_pending = False;
5383 struct timespec write_time_ts;
5384 files_struct *fsp = NULL;
5385 struct file_id fileid;
5386 struct ea_list *ea_list = NULL;
5387 int lock_data_count = 0;
5388 char *lock_data = NULL;
5389 size_t fixed_portion;
5390 NTSTATUS status = NT_STATUS_OK;
5392 if (!params) {
5393 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5394 return;
5397 ZERO_STRUCT(write_time_ts);
5399 if (tran_call == TRANSACT2_QFILEINFO) {
5400 if (total_params < 4) {
5401 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5402 return;
5405 if (IS_IPC(conn)) {
5406 call_trans2qpipeinfo(conn, req, tran_call,
5407 pparams, total_params,
5408 ppdata, total_data,
5409 max_data_bytes);
5410 return;
5413 fsp = file_fsp(req, SVAL(params,0));
5414 info_level = SVAL(params,2);
5416 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
5418 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
5419 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5420 return;
5423 /* Initial check for valid fsp ptr. */
5424 if (!check_fsp_open(conn, req, fsp)) {
5425 return;
5428 smb_fname = cp_smb_filename(talloc_tos(), fsp->fsp_name);
5429 if (smb_fname == NULL) {
5430 reply_nterror(req, NT_STATUS_NO_MEMORY);
5431 return;
5434 if(fsp->fake_file_handle) {
5436 * This is actually for the QUOTA_FAKE_FILE --metze
5439 /* We know this name is ok, it's already passed the checks. */
5441 } else if(fsp->fh->fd == -1) {
5443 * This is actually a QFILEINFO on a directory
5444 * handle (returned from an NT SMB). NT5.0 seems
5445 * to do this call. JRA.
5448 if (INFO_LEVEL_IS_UNIX(info_level)) {
5449 /* Always do lstat for UNIX calls. */
5450 if (SMB_VFS_LSTAT(conn, smb_fname)) {
5451 DEBUG(3,("call_trans2qfilepathinfo: "
5452 "SMB_VFS_LSTAT of %s failed "
5453 "(%s)\n",
5454 smb_fname_str_dbg(smb_fname),
5455 strerror(errno)));
5456 reply_nterror(req,
5457 map_nt_error_from_unix(errno));
5458 return;
5460 } else if (SMB_VFS_STAT(conn, smb_fname)) {
5461 DEBUG(3,("call_trans2qfilepathinfo: "
5462 "SMB_VFS_STAT of %s failed (%s)\n",
5463 smb_fname_str_dbg(smb_fname),
5464 strerror(errno)));
5465 reply_nterror(req,
5466 map_nt_error_from_unix(errno));
5467 return;
5470 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5471 get_file_infos(fileid, fsp->name_hash, &delete_pending, &write_time_ts);
5472 } else {
5474 * Original code - this is an open file.
5476 if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
5477 DEBUG(3, ("fstat of %s failed (%s)\n",
5478 fsp_fnum_dbg(fsp), strerror(errno)));
5479 reply_nterror(req,
5480 map_nt_error_from_unix(errno));
5481 return;
5483 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5484 get_file_infos(fileid, fsp->name_hash, &delete_pending, &write_time_ts);
5487 } else {
5488 uint32_t name_hash;
5489 char *fname = NULL;
5490 uint32_t ucf_flags = 0;
5492 /* qpathinfo */
5493 if (total_params < 7) {
5494 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5495 return;
5498 info_level = SVAL(params,0);
5500 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
5502 if (INFO_LEVEL_IS_UNIX(info_level)) {
5503 if (!lp_unix_extensions()) {
5504 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5505 return;
5507 if (info_level == SMB_QUERY_FILE_UNIX_BASIC ||
5508 info_level == SMB_QUERY_FILE_UNIX_INFO2 ||
5509 info_level == SMB_QUERY_FILE_UNIX_LINK) {
5510 ucf_flags |= UCF_UNIX_NAME_LOOKUP;
5514 srvstr_get_path(req, params, req->flags2, &fname, &params[6],
5515 total_params - 6,
5516 STR_TERMINATE, &status);
5517 if (!NT_STATUS_IS_OK(status)) {
5518 reply_nterror(req, status);
5519 return;
5522 status = filename_convert(req,
5523 conn,
5524 req->flags2 & FLAGS2_DFS_PATHNAMES,
5525 fname,
5526 ucf_flags,
5527 NULL,
5528 &smb_fname);
5529 if (!NT_STATUS_IS_OK(status)) {
5530 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5531 reply_botherror(req,
5532 NT_STATUS_PATH_NOT_COVERED,
5533 ERRSRV, ERRbadpath);
5534 return;
5536 reply_nterror(req, status);
5537 return;
5540 /* If this is a stream, check if there is a delete_pending. */
5541 if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
5542 && is_ntfs_stream_smb_fname(smb_fname)) {
5543 struct smb_filename *smb_fname_base;
5545 /* Create an smb_filename with stream_name == NULL. */
5546 smb_fname_base = synthetic_smb_fname(
5547 talloc_tos(), smb_fname->base_name,
5548 NULL, NULL);
5549 if (smb_fname_base == NULL) {
5550 reply_nterror(req, NT_STATUS_NO_MEMORY);
5551 return;
5554 if (INFO_LEVEL_IS_UNIX(info_level)) {
5555 /* Always do lstat for UNIX calls. */
5556 if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) {
5557 DEBUG(3,("call_trans2qfilepathinfo: "
5558 "SMB_VFS_LSTAT of %s failed "
5559 "(%s)\n",
5560 smb_fname_str_dbg(smb_fname_base),
5561 strerror(errno)));
5562 TALLOC_FREE(smb_fname_base);
5563 reply_nterror(req,
5564 map_nt_error_from_unix(errno));
5565 return;
5567 } else {
5568 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
5569 DEBUG(3,("call_trans2qfilepathinfo: "
5570 "fileinfo of %s failed "
5571 "(%s)\n",
5572 smb_fname_str_dbg(smb_fname_base),
5573 strerror(errno)));
5574 TALLOC_FREE(smb_fname_base);
5575 reply_nterror(req,
5576 map_nt_error_from_unix(errno));
5577 return;
5581 status = file_name_hash(conn,
5582 smb_fname_str_dbg(smb_fname_base),
5583 &name_hash);
5584 if (!NT_STATUS_IS_OK(status)) {
5585 TALLOC_FREE(smb_fname_base);
5586 reply_nterror(req, status);
5587 return;
5590 fileid = vfs_file_id_from_sbuf(conn,
5591 &smb_fname_base->st);
5592 TALLOC_FREE(smb_fname_base);
5593 get_file_infos(fileid, name_hash, &delete_pending, NULL);
5594 if (delete_pending) {
5595 reply_nterror(req, NT_STATUS_DELETE_PENDING);
5596 return;
5600 if (INFO_LEVEL_IS_UNIX(info_level)) {
5601 /* Always do lstat for UNIX calls. */
5602 if (SMB_VFS_LSTAT(conn, smb_fname)) {
5603 DEBUG(3,("call_trans2qfilepathinfo: "
5604 "SMB_VFS_LSTAT of %s failed (%s)\n",
5605 smb_fname_str_dbg(smb_fname),
5606 strerror(errno)));
5607 reply_nterror(req,
5608 map_nt_error_from_unix(errno));
5609 return;
5612 } else {
5613 if (SMB_VFS_STAT(conn, smb_fname) != 0) {
5614 DEBUG(3,("call_trans2qfilepathinfo: "
5615 "SMB_VFS_STAT of %s failed (%s)\n",
5616 smb_fname_str_dbg(smb_fname),
5617 strerror(errno)));
5618 reply_nterror(req,
5619 map_nt_error_from_unix(errno));
5620 return;
5624 status = file_name_hash(conn,
5625 smb_fname_str_dbg(smb_fname),
5626 &name_hash);
5627 if (!NT_STATUS_IS_OK(status)) {
5628 reply_nterror(req, status);
5629 return;
5632 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5633 get_file_infos(fileid, name_hash, &delete_pending, &write_time_ts);
5634 if (delete_pending) {
5635 reply_nterror(req, NT_STATUS_DELETE_PENDING);
5636 return;
5640 DEBUG(3,("call_trans2qfilepathinfo %s (%s) level=%d call=%d "
5641 "total_data=%d\n", smb_fname_str_dbg(smb_fname),
5642 fsp_fnum_dbg(fsp),
5643 info_level,tran_call,total_data));
5645 /* Pull out any data sent here before we realloc. */
5646 switch (info_level) {
5647 case SMB_INFO_QUERY_EAS_FROM_LIST:
5649 /* Pull any EA list from the data portion. */
5650 uint32 ea_size;
5652 if (total_data < 4) {
5653 reply_nterror(
5654 req, NT_STATUS_INVALID_PARAMETER);
5655 return;
5657 ea_size = IVAL(pdata,0);
5659 if (total_data > 0 && ea_size != total_data) {
5660 DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
5661 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
5662 reply_nterror(
5663 req, NT_STATUS_INVALID_PARAMETER);
5664 return;
5667 if (!lp_ea_support(SNUM(conn))) {
5668 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
5669 return;
5672 /* Pull out the list of names. */
5673 ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4);
5674 if (!ea_list) {
5675 reply_nterror(
5676 req, NT_STATUS_INVALID_PARAMETER);
5677 return;
5679 break;
5682 case SMB_QUERY_POSIX_LOCK:
5684 if (fsp == NULL || fsp->fh->fd == -1) {
5685 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5686 return;
5689 if (total_data != POSIX_LOCK_DATA_SIZE) {
5690 reply_nterror(
5691 req, NT_STATUS_INVALID_PARAMETER);
5692 return;
5695 /* Copy the lock range data. */
5696 lock_data = (char *)talloc_memdup(
5697 req, pdata, total_data);
5698 if (!lock_data) {
5699 reply_nterror(req, NT_STATUS_NO_MEMORY);
5700 return;
5702 lock_data_count = total_data;
5704 default:
5705 break;
5708 *pparams = (char *)SMB_REALLOC(*pparams,2);
5709 if (*pparams == NULL) {
5710 reply_nterror(req, NT_STATUS_NO_MEMORY);
5711 return;
5713 params = *pparams;
5714 SSVAL(params,0,0);
5717 * draft-leach-cifs-v1-spec-02.txt
5718 * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path
5719 * says:
5721 * The requested information is placed in the Data portion of the
5722 * transaction response. For the information levels greater than 0x100,
5723 * the transaction response has 1 parameter word which should be
5724 * ignored by the client.
5726 * However Windows only follows this rule for the IS_NAME_VALID call.
5728 switch (info_level) {
5729 case SMB_INFO_IS_NAME_VALID:
5730 param_size = 0;
5731 break;
5734 if ((info_level & 0xFF00) == 0xFF00) {
5736 * We use levels that start with 0xFF00
5737 * internally to represent SMB2 specific levels
5739 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5740 return;
5743 status = smbd_do_qfilepathinfo(conn, req, info_level,
5744 fsp, smb_fname,
5745 delete_pending, write_time_ts,
5746 ea_list,
5747 lock_data_count, lock_data,
5748 req->flags2, max_data_bytes,
5749 &fixed_portion,
5750 ppdata, &data_size);
5751 if (!NT_STATUS_IS_OK(status)) {
5752 reply_nterror(req, status);
5753 return;
5755 if (fixed_portion > max_data_bytes) {
5756 reply_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
5757 return;
5760 send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
5761 max_data_bytes);
5763 return;
5766 /****************************************************************************
5767 Set a hard link (called by UNIX extensions and by NT rename with HARD link
5768 code.
5769 ****************************************************************************/
5771 NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
5772 connection_struct *conn,
5773 struct smb_request *req,
5774 bool overwrite_if_exists,
5775 const struct smb_filename *smb_fname_old,
5776 struct smb_filename *smb_fname_new)
5778 NTSTATUS status = NT_STATUS_OK;
5780 /* source must already exist. */
5781 if (!VALID_STAT(smb_fname_old->st)) {
5782 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5785 if (VALID_STAT(smb_fname_new->st)) {
5786 if (overwrite_if_exists) {
5787 if (S_ISDIR(smb_fname_new->st.st_ex_mode)) {
5788 return NT_STATUS_FILE_IS_A_DIRECTORY;
5790 status = unlink_internals(conn,
5791 req,
5792 FILE_ATTRIBUTE_NORMAL,
5793 smb_fname_new,
5794 false);
5795 if (!NT_STATUS_IS_OK(status)) {
5796 return status;
5798 } else {
5799 /* Disallow if newname already exists. */
5800 return NT_STATUS_OBJECT_NAME_COLLISION;
5804 /* No links from a directory. */
5805 if (S_ISDIR(smb_fname_old->st.st_ex_mode)) {
5806 return NT_STATUS_FILE_IS_A_DIRECTORY;
5809 /* Setting a hardlink to/from a stream isn't currently supported. */
5810 if (is_ntfs_stream_smb_fname(smb_fname_old) ||
5811 is_ntfs_stream_smb_fname(smb_fname_new)) {
5812 return NT_STATUS_INVALID_PARAMETER;
5815 DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n",
5816 smb_fname_old->base_name, smb_fname_new->base_name));
5818 if (SMB_VFS_LINK(conn, smb_fname_old->base_name,
5819 smb_fname_new->base_name) != 0) {
5820 status = map_nt_error_from_unix(errno);
5821 DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
5822 nt_errstr(status), smb_fname_old->base_name,
5823 smb_fname_new->base_name));
5825 return status;
5828 /****************************************************************************
5829 Deal with setting the time from any of the setfilepathinfo functions.
5830 NOTE !!!! The check for FILE_WRITE_ATTRIBUTES access must be done *before*
5831 calling this function.
5832 ****************************************************************************/
5834 NTSTATUS smb_set_file_time(connection_struct *conn,
5835 files_struct *fsp,
5836 const struct smb_filename *smb_fname,
5837 struct smb_file_time *ft,
5838 bool setting_write_time)
5840 struct smb_filename smb_fname_base;
5841 uint32 action =
5842 FILE_NOTIFY_CHANGE_LAST_ACCESS
5843 |FILE_NOTIFY_CHANGE_LAST_WRITE
5844 |FILE_NOTIFY_CHANGE_CREATION;
5846 if (!VALID_STAT(smb_fname->st)) {
5847 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5850 /* get some defaults (no modifications) if any info is zero or -1. */
5851 if (null_timespec(ft->create_time)) {
5852 action &= ~FILE_NOTIFY_CHANGE_CREATION;
5855 if (null_timespec(ft->atime)) {
5856 action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
5859 if (null_timespec(ft->mtime)) {
5860 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
5863 if (!setting_write_time) {
5864 /* ft->mtime comes from change time, not write time. */
5865 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
5868 /* Ensure the resolution is the correct for
5869 * what we can store on this filesystem. */
5871 round_timespec(conn->ts_res, &ft->create_time);
5872 round_timespec(conn->ts_res, &ft->ctime);
5873 round_timespec(conn->ts_res, &ft->atime);
5874 round_timespec(conn->ts_res, &ft->mtime);
5876 DEBUG(5,("smb_set_filetime: actime: %s\n ",
5877 time_to_asc(convert_timespec_to_time_t(ft->atime))));
5878 DEBUG(5,("smb_set_filetime: modtime: %s\n ",
5879 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
5880 DEBUG(5,("smb_set_filetime: ctime: %s\n ",
5881 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
5882 DEBUG(5,("smb_set_file_time: createtime: %s\n ",
5883 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
5885 if (setting_write_time) {
5887 * This was a Windows setfileinfo on an open file.
5888 * NT does this a lot. We also need to
5889 * set the time here, as it can be read by
5890 * FindFirst/FindNext and with the patch for bug #2045
5891 * in smbd/fileio.c it ensures that this timestamp is
5892 * kept sticky even after a write. We save the request
5893 * away and will set it on file close and after a write. JRA.
5896 DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n",
5897 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
5899 if (fsp != NULL) {
5900 if (fsp->base_fsp) {
5901 set_sticky_write_time_fsp(fsp->base_fsp,
5902 ft->mtime);
5903 } else {
5904 set_sticky_write_time_fsp(fsp, ft->mtime);
5906 } else {
5907 set_sticky_write_time_path(
5908 vfs_file_id_from_sbuf(conn, &smb_fname->st),
5909 ft->mtime);
5913 DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
5915 /* Always call ntimes on the base, even if a stream was passed in. */
5916 smb_fname_base = *smb_fname;
5917 smb_fname_base.stream_name = NULL;
5919 if(file_ntimes(conn, &smb_fname_base, ft)!=0) {
5920 return map_nt_error_from_unix(errno);
5923 notify_fname(conn, NOTIFY_ACTION_MODIFIED, action,
5924 smb_fname->base_name);
5925 return NT_STATUS_OK;
5928 /****************************************************************************
5929 Deal with setting the dosmode from any of the setfilepathinfo functions.
5930 NB. The check for FILE_WRITE_ATTRIBUTES access on this path must have been
5931 done before calling this function.
5932 ****************************************************************************/
5934 static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
5935 const struct smb_filename *smb_fname,
5936 uint32 dosmode)
5938 struct smb_filename *smb_fname_base;
5939 NTSTATUS status;
5941 if (!VALID_STAT(smb_fname->st)) {
5942 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5945 /* Always operate on the base_name, even if a stream was passed in. */
5946 smb_fname_base = synthetic_smb_fname(
5947 talloc_tos(), smb_fname->base_name, NULL, &smb_fname->st);
5948 if (smb_fname_base == NULL) {
5949 return NT_STATUS_NO_MEMORY;
5952 if (dosmode) {
5953 if (S_ISDIR(smb_fname_base->st.st_ex_mode)) {
5954 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
5955 } else {
5956 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
5960 DEBUG(6,("smb_set_file_dosmode: dosmode: 0x%x\n", (unsigned int)dosmode));
5962 /* check the mode isn't different, before changing it */
5963 if ((dosmode != 0) && (dosmode != dos_mode(conn, smb_fname_base))) {
5964 DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode "
5965 "0x%x\n", smb_fname_str_dbg(smb_fname_base),
5966 (unsigned int)dosmode));
5968 if(file_set_dosmode(conn, smb_fname_base, dosmode, NULL,
5969 false)) {
5970 DEBUG(2,("smb_set_file_dosmode: file_set_dosmode of "
5971 "%s failed (%s)\n",
5972 smb_fname_str_dbg(smb_fname_base),
5973 strerror(errno)));
5974 status = map_nt_error_from_unix(errno);
5975 goto out;
5978 status = NT_STATUS_OK;
5979 out:
5980 TALLOC_FREE(smb_fname_base);
5981 return status;
5984 /****************************************************************************
5985 Deal with setting the size from any of the setfilepathinfo functions.
5986 ****************************************************************************/
5988 static NTSTATUS smb_set_file_size(connection_struct *conn,
5989 struct smb_request *req,
5990 files_struct *fsp,
5991 const struct smb_filename *smb_fname,
5992 const SMB_STRUCT_STAT *psbuf,
5993 off_t size,
5994 bool fail_after_createfile)
5996 NTSTATUS status = NT_STATUS_OK;
5997 struct smb_filename *smb_fname_tmp = NULL;
5998 files_struct *new_fsp = NULL;
6000 if (!VALID_STAT(*psbuf)) {
6001 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6004 DEBUG(6,("smb_set_file_size: size: %.0f ", (double)size));
6006 if (size == get_file_size_stat(psbuf)) {
6007 return NT_STATUS_OK;
6010 DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n",
6011 smb_fname_str_dbg(smb_fname), (double)size));
6013 if (fsp && fsp->fh->fd != -1) {
6014 /* Handle based call. */
6015 if (!(fsp->access_mask & FILE_WRITE_DATA)) {
6016 return NT_STATUS_ACCESS_DENIED;
6019 if (vfs_set_filelen(fsp, size) == -1) {
6020 return map_nt_error_from_unix(errno);
6022 trigger_write_time_update_immediate(fsp);
6023 return NT_STATUS_OK;
6026 smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
6027 if (smb_fname_tmp == NULL) {
6028 return NT_STATUS_NO_MEMORY;
6031 smb_fname_tmp->st = *psbuf;
6033 status = SMB_VFS_CREATE_FILE(
6034 conn, /* conn */
6035 req, /* req */
6036 0, /* root_dir_fid */
6037 smb_fname_tmp, /* fname */
6038 FILE_WRITE_DATA, /* access_mask */
6039 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6040 FILE_SHARE_DELETE),
6041 FILE_OPEN, /* create_disposition*/
6042 0, /* create_options */
6043 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6044 0, /* oplock_request */
6045 NULL, /* lease */
6046 0, /* allocation_size */
6047 0, /* private_flags */
6048 NULL, /* sd */
6049 NULL, /* ea_list */
6050 &new_fsp, /* result */
6051 NULL, /* pinfo */
6052 NULL, NULL); /* create context */
6054 TALLOC_FREE(smb_fname_tmp);
6056 if (!NT_STATUS_IS_OK(status)) {
6057 /* NB. We check for open_was_deferred in the caller. */
6058 return status;
6061 /* See RAW-SFILEINFO-END-OF-FILE */
6062 if (fail_after_createfile) {
6063 close_file(req, new_fsp,NORMAL_CLOSE);
6064 return NT_STATUS_INVALID_LEVEL;
6067 if (vfs_set_filelen(new_fsp, size) == -1) {
6068 status = map_nt_error_from_unix(errno);
6069 close_file(req, new_fsp,NORMAL_CLOSE);
6070 return status;
6073 trigger_write_time_update_immediate(new_fsp);
6074 close_file(req, new_fsp,NORMAL_CLOSE);
6075 return NT_STATUS_OK;
6078 /****************************************************************************
6079 Deal with SMB_INFO_SET_EA.
6080 ****************************************************************************/
6082 static NTSTATUS smb_info_set_ea(connection_struct *conn,
6083 const char *pdata,
6084 int total_data,
6085 files_struct *fsp,
6086 const struct smb_filename *smb_fname)
6088 struct ea_list *ea_list = NULL;
6089 TALLOC_CTX *ctx = NULL;
6090 NTSTATUS status = NT_STATUS_OK;
6092 if (total_data < 10) {
6094 /* OS/2 workplace shell seems to send SET_EA requests of "null"
6095 length. They seem to have no effect. Bug #3212. JRA */
6097 if ((total_data == 4) && (IVAL(pdata,0) == 4)) {
6098 /* We're done. We only get EA info in this call. */
6099 return NT_STATUS_OK;
6102 return NT_STATUS_INVALID_PARAMETER;
6105 if (IVAL(pdata,0) > total_data) {
6106 DEBUG(10,("smb_info_set_ea: bad total data size (%u) > %u\n",
6107 IVAL(pdata,0), (unsigned int)total_data));
6108 return NT_STATUS_INVALID_PARAMETER;
6111 ctx = talloc_tos();
6112 ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
6113 if (!ea_list) {
6114 return NT_STATUS_INVALID_PARAMETER;
6117 status = set_ea(conn, fsp, smb_fname, ea_list);
6119 return status;
6122 /****************************************************************************
6123 Deal with SMB_FILE_FULL_EA_INFORMATION set.
6124 ****************************************************************************/
6126 static NTSTATUS smb_set_file_full_ea_info(connection_struct *conn,
6127 const char *pdata,
6128 int total_data,
6129 files_struct *fsp)
6131 struct ea_list *ea_list = NULL;
6132 NTSTATUS status;
6134 if (!fsp) {
6135 return NT_STATUS_INVALID_HANDLE;
6138 if (!lp_ea_support(SNUM(conn))) {
6139 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u but "
6140 "EA's not supported.\n",
6141 (unsigned int)total_data));
6142 return NT_STATUS_EAS_NOT_SUPPORTED;
6145 if (total_data < 10) {
6146 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u "
6147 "too small.\n",
6148 (unsigned int)total_data));
6149 return NT_STATUS_INVALID_PARAMETER;
6152 ea_list = read_nttrans_ea_list(talloc_tos(),
6153 pdata,
6154 total_data);
6156 if (!ea_list) {
6157 return NT_STATUS_INVALID_PARAMETER;
6160 status = set_ea(conn, fsp, fsp->fsp_name, ea_list);
6162 DEBUG(10, ("smb_set_file_full_ea_info on file %s returned %s\n",
6163 smb_fname_str_dbg(fsp->fsp_name),
6164 nt_errstr(status) ));
6166 return status;
6170 /****************************************************************************
6171 Deal with SMB_SET_FILE_DISPOSITION_INFO.
6172 ****************************************************************************/
6174 static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
6175 const char *pdata,
6176 int total_data,
6177 files_struct *fsp,
6178 struct smb_filename *smb_fname)
6180 NTSTATUS status = NT_STATUS_OK;
6181 bool delete_on_close;
6182 uint32 dosmode = 0;
6184 if (total_data < 1) {
6185 return NT_STATUS_INVALID_PARAMETER;
6188 if (fsp == NULL) {
6189 return NT_STATUS_INVALID_HANDLE;
6192 delete_on_close = (CVAL(pdata,0) ? True : False);
6193 dosmode = dos_mode(conn, smb_fname);
6195 DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
6196 "delete_on_close = %u\n",
6197 smb_fname_str_dbg(smb_fname),
6198 (unsigned int)dosmode,
6199 (unsigned int)delete_on_close ));
6201 if (delete_on_close) {
6202 status = can_set_delete_on_close(fsp, dosmode);
6203 if (!NT_STATUS_IS_OK(status)) {
6204 return status;
6208 /* The set is across all open files on this dev/inode pair. */
6209 if (!set_delete_on_close(fsp, delete_on_close,
6210 conn->session_info->security_token,
6211 conn->session_info->unix_token)) {
6212 return NT_STATUS_ACCESS_DENIED;
6214 return NT_STATUS_OK;
6217 /****************************************************************************
6218 Deal with SMB_FILE_POSITION_INFORMATION.
6219 ****************************************************************************/
6221 static NTSTATUS smb_file_position_information(connection_struct *conn,
6222 const char *pdata,
6223 int total_data,
6224 files_struct *fsp)
6226 uint64_t position_information;
6228 if (total_data < 8) {
6229 return NT_STATUS_INVALID_PARAMETER;
6232 if (fsp == NULL) {
6233 /* Ignore on pathname based set. */
6234 return NT_STATUS_OK;
6237 position_information = (uint64_t)IVAL(pdata,0);
6238 position_information |= (((uint64_t)IVAL(pdata,4)) << 32);
6240 DEBUG(10,("smb_file_position_information: Set file position "
6241 "information for file %s to %.0f\n", fsp_str_dbg(fsp),
6242 (double)position_information));
6243 fsp->fh->position_information = position_information;
6244 return NT_STATUS_OK;
6247 /****************************************************************************
6248 Deal with SMB_FILE_MODE_INFORMATION.
6249 ****************************************************************************/
6251 static NTSTATUS smb_file_mode_information(connection_struct *conn,
6252 const char *pdata,
6253 int total_data)
6255 uint32 mode;
6257 if (total_data < 4) {
6258 return NT_STATUS_INVALID_PARAMETER;
6260 mode = IVAL(pdata,0);
6261 if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
6262 return NT_STATUS_INVALID_PARAMETER;
6264 return NT_STATUS_OK;
6267 /****************************************************************************
6268 Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
6269 ****************************************************************************/
6271 static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
6272 struct smb_request *req,
6273 const char *pdata,
6274 int total_data,
6275 const struct smb_filename *smb_fname)
6277 char *link_target = NULL;
6278 const char *newname = smb_fname->base_name;
6279 TALLOC_CTX *ctx = talloc_tos();
6281 /* Set a symbolic link. */
6282 /* Don't allow this if follow links is false. */
6284 if (total_data == 0) {
6285 return NT_STATUS_INVALID_PARAMETER;
6288 if (!lp_follow_symlinks(SNUM(conn))) {
6289 return NT_STATUS_ACCESS_DENIED;
6292 srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
6293 total_data, STR_TERMINATE);
6295 if (!link_target) {
6296 return NT_STATUS_INVALID_PARAMETER;
6299 DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
6300 newname, link_target ));
6302 if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0) {
6303 return map_nt_error_from_unix(errno);
6306 return NT_STATUS_OK;
6309 /****************************************************************************
6310 Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
6311 ****************************************************************************/
6313 static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
6314 struct smb_request *req,
6315 const char *pdata, int total_data,
6316 struct smb_filename *smb_fname_new)
6318 char *oldname = NULL;
6319 struct smb_filename *smb_fname_old = NULL;
6320 TALLOC_CTX *ctx = talloc_tos();
6321 NTSTATUS status = NT_STATUS_OK;
6323 /* Set a hard link. */
6324 if (total_data == 0) {
6325 return NT_STATUS_INVALID_PARAMETER;
6328 srvstr_get_path(ctx, pdata, req->flags2, &oldname, pdata,
6329 total_data, STR_TERMINATE, &status);
6330 if (!NT_STATUS_IS_OK(status)) {
6331 return status;
6334 DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
6335 smb_fname_str_dbg(smb_fname_new), oldname));
6337 status = filename_convert(ctx,
6338 conn,
6339 req->flags2 & FLAGS2_DFS_PATHNAMES,
6340 oldname,
6342 NULL,
6343 &smb_fname_old);
6344 if (!NT_STATUS_IS_OK(status)) {
6345 return status;
6348 return hardlink_internals(ctx, conn, req, false,
6349 smb_fname_old, smb_fname_new);
6352 /****************************************************************************
6353 Deal with SMB2_FILE_RENAME_INFORMATION_INTERNAL
6354 ****************************************************************************/
6356 static NTSTATUS smb2_file_rename_information(connection_struct *conn,
6357 struct smb_request *req,
6358 const char *pdata,
6359 int total_data,
6360 files_struct *fsp,
6361 struct smb_filename *smb_fname_src)
6363 bool overwrite;
6364 uint32_t len;
6365 char *newname = NULL;
6366 struct smb_filename *smb_fname_dst = NULL;
6367 NTSTATUS status = NT_STATUS_OK;
6368 TALLOC_CTX *ctx = talloc_tos();
6370 if (!fsp) {
6371 return NT_STATUS_INVALID_HANDLE;
6374 if (total_data < 20) {
6375 return NT_STATUS_INVALID_PARAMETER;
6378 overwrite = (CVAL(pdata,0) ? True : False);
6379 len = IVAL(pdata,16);
6381 if (len > (total_data - 20) || (len == 0)) {
6382 return NT_STATUS_INVALID_PARAMETER;
6385 srvstr_get_path(ctx, pdata, req->flags2, &newname,
6386 &pdata[20], len, STR_TERMINATE,
6387 &status);
6388 if (!NT_STATUS_IS_OK(status)) {
6389 return status;
6392 DEBUG(10,("smb2_file_rename_information: got name |%s|\n",
6393 newname));
6395 status = filename_convert(ctx,
6396 conn,
6397 req->flags2 & FLAGS2_DFS_PATHNAMES,
6398 newname,
6399 UCF_SAVE_LCOMP,
6400 NULL,
6401 &smb_fname_dst);
6402 if (!NT_STATUS_IS_OK(status)) {
6403 return status;
6406 if (fsp->base_fsp) {
6407 /* newname must be a stream name. */
6408 if (newname[0] != ':') {
6409 return NT_STATUS_NOT_SUPPORTED;
6412 /* Create an smb_fname to call rename_internals_fsp() with. */
6413 smb_fname_dst = synthetic_smb_fname(
6414 talloc_tos(), fsp->base_fsp->fsp_name->base_name,
6415 newname, NULL);
6416 if (smb_fname_dst == NULL) {
6417 status = NT_STATUS_NO_MEMORY;
6418 goto out;
6422 * Set the original last component, since
6423 * rename_internals_fsp() requires it.
6425 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6426 newname);
6427 if (smb_fname_dst->original_lcomp == NULL) {
6428 status = NT_STATUS_NO_MEMORY;
6429 goto out;
6434 DEBUG(10,("smb2_file_rename_information: "
6435 "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
6436 fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
6437 smb_fname_str_dbg(smb_fname_dst)));
6438 status = rename_internals_fsp(conn, fsp, smb_fname_dst,
6439 (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM),
6440 overwrite);
6442 out:
6443 TALLOC_FREE(smb_fname_dst);
6444 return status;
6447 static NTSTATUS smb_file_link_information(connection_struct *conn,
6448 struct smb_request *req,
6449 const char *pdata,
6450 int total_data,
6451 files_struct *fsp,
6452 struct smb_filename *smb_fname_src)
6454 bool overwrite;
6455 uint32_t len;
6456 char *newname = NULL;
6457 struct smb_filename *smb_fname_dst = NULL;
6458 NTSTATUS status = NT_STATUS_OK;
6459 TALLOC_CTX *ctx = talloc_tos();
6461 if (!fsp) {
6462 return NT_STATUS_INVALID_HANDLE;
6465 if (total_data < 20) {
6466 return NT_STATUS_INVALID_PARAMETER;
6469 overwrite = (CVAL(pdata,0) ? true : false);
6470 len = IVAL(pdata,16);
6472 if (len > (total_data - 20) || (len == 0)) {
6473 return NT_STATUS_INVALID_PARAMETER;
6476 srvstr_get_path(ctx, pdata, req->flags2, &newname,
6477 &pdata[20], len, STR_TERMINATE,
6478 &status);
6479 if (!NT_STATUS_IS_OK(status)) {
6480 return status;
6483 DEBUG(10,("smb_file_link_information: got name |%s|\n",
6484 newname));
6486 status = filename_convert(ctx,
6487 conn,
6488 req->flags2 & FLAGS2_DFS_PATHNAMES,
6489 newname,
6490 UCF_SAVE_LCOMP,
6491 NULL,
6492 &smb_fname_dst);
6493 if (!NT_STATUS_IS_OK(status)) {
6494 return status;
6497 if (fsp->base_fsp) {
6498 /* No stream names. */
6499 return NT_STATUS_NOT_SUPPORTED;
6502 DEBUG(10,("smb_file_link_information: "
6503 "SMB_FILE_LINK_INFORMATION (%s) %s -> %s\n",
6504 fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
6505 smb_fname_str_dbg(smb_fname_dst)));
6506 status = hardlink_internals(ctx,
6507 conn,
6508 req,
6509 overwrite,
6510 fsp->fsp_name,
6511 smb_fname_dst);
6513 TALLOC_FREE(smb_fname_dst);
6514 return status;
6517 /****************************************************************************
6518 Deal with SMB_FILE_RENAME_INFORMATION.
6519 ****************************************************************************/
6521 static NTSTATUS smb_file_rename_information(connection_struct *conn,
6522 struct smb_request *req,
6523 const char *pdata,
6524 int total_data,
6525 files_struct *fsp,
6526 struct smb_filename *smb_fname_src)
6528 bool overwrite;
6529 uint32 root_fid;
6530 uint32 len;
6531 char *newname = NULL;
6532 struct smb_filename *smb_fname_dst = NULL;
6533 bool dest_has_wcard = False;
6534 NTSTATUS status = NT_STATUS_OK;
6535 char *p;
6536 TALLOC_CTX *ctx = talloc_tos();
6538 if (total_data < 13) {
6539 return NT_STATUS_INVALID_PARAMETER;
6542 overwrite = (CVAL(pdata,0) ? True : False);
6543 root_fid = IVAL(pdata,4);
6544 len = IVAL(pdata,8);
6546 if (len > (total_data - 12) || (len == 0) || (root_fid != 0)) {
6547 return NT_STATUS_INVALID_PARAMETER;
6550 srvstr_get_path_wcard(ctx, pdata, req->flags2, &newname, &pdata[12],
6551 len, 0, &status,
6552 &dest_has_wcard);
6553 if (!NT_STATUS_IS_OK(status)) {
6554 return status;
6557 DEBUG(10,("smb_file_rename_information: got name |%s|\n",
6558 newname));
6560 status = resolve_dfspath_wcard(ctx, conn,
6561 req->flags2 & FLAGS2_DFS_PATHNAMES,
6562 newname,
6563 true,
6564 !conn->sconn->using_smb2,
6565 &newname,
6566 &dest_has_wcard);
6567 if (!NT_STATUS_IS_OK(status)) {
6568 return status;
6571 /* Check the new name has no '/' characters. */
6572 if (strchr_m(newname, '/')) {
6573 return NT_STATUS_NOT_SUPPORTED;
6576 if (fsp && fsp->base_fsp) {
6577 /* newname must be a stream name. */
6578 if (newname[0] != ':') {
6579 return NT_STATUS_NOT_SUPPORTED;
6582 /* Create an smb_fname to call rename_internals_fsp() with. */
6583 smb_fname_dst = synthetic_smb_fname(
6584 talloc_tos(), fsp->base_fsp->fsp_name->base_name,
6585 newname, NULL);
6586 if (smb_fname_dst == NULL) {
6587 status = NT_STATUS_NO_MEMORY;
6588 goto out;
6592 * Set the original last component, since
6593 * rename_internals_fsp() requires it.
6595 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6596 newname);
6597 if (smb_fname_dst->original_lcomp == NULL) {
6598 status = NT_STATUS_NO_MEMORY;
6599 goto out;
6602 } else {
6604 * Build up an smb_fname_dst based on the filename passed in.
6605 * We basically just strip off the last component, and put on
6606 * the newname instead.
6608 char *base_name = NULL;
6610 /* newname must *not* be a stream name. */
6611 if (newname[0] == ':') {
6612 return NT_STATUS_NOT_SUPPORTED;
6616 * Strip off the last component (filename) of the path passed
6617 * in.
6619 base_name = talloc_strdup(ctx, smb_fname_src->base_name);
6620 if (!base_name) {
6621 return NT_STATUS_NO_MEMORY;
6623 p = strrchr_m(base_name, '/');
6624 if (p) {
6625 p[1] = '\0';
6626 } else {
6627 base_name = talloc_strdup(ctx, "");
6628 if (!base_name) {
6629 return NT_STATUS_NO_MEMORY;
6632 /* Append the new name. */
6633 base_name = talloc_asprintf_append(base_name,
6634 "%s",
6635 newname);
6636 if (!base_name) {
6637 return NT_STATUS_NO_MEMORY;
6640 status = unix_convert(ctx, conn, base_name, &smb_fname_dst,
6641 (UCF_SAVE_LCOMP |
6642 (dest_has_wcard ?
6643 UCF_ALWAYS_ALLOW_WCARD_LCOMP :
6644 0)));
6646 /* If an error we expect this to be
6647 * NT_STATUS_OBJECT_PATH_NOT_FOUND */
6649 if (!NT_STATUS_IS_OK(status)) {
6650 if(!NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
6651 status)) {
6652 goto out;
6654 /* Create an smb_fname to call rename_internals_fsp() */
6655 smb_fname_dst = synthetic_smb_fname(
6656 ctx, base_name, NULL, NULL);
6657 if (smb_fname_dst == NULL) {
6658 status = NT_STATUS_NO_MEMORY;
6659 goto out;
6664 if (fsp) {
6665 DEBUG(10,("smb_file_rename_information: "
6666 "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
6667 fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
6668 smb_fname_str_dbg(smb_fname_dst)));
6669 status = rename_internals_fsp(conn, fsp, smb_fname_dst, 0,
6670 overwrite);
6671 } else {
6672 DEBUG(10,("smb_file_rename_information: "
6673 "SMB_FILE_RENAME_INFORMATION %s -> %s\n",
6674 smb_fname_str_dbg(smb_fname_src),
6675 smb_fname_str_dbg(smb_fname_dst)));
6676 status = rename_internals(ctx, conn, req, smb_fname_src,
6677 smb_fname_dst, 0, overwrite, false,
6678 dest_has_wcard,
6679 FILE_WRITE_ATTRIBUTES);
6681 out:
6682 TALLOC_FREE(smb_fname_dst);
6683 return status;
6686 /****************************************************************************
6687 Deal with SMB_SET_POSIX_ACL.
6688 ****************************************************************************/
6690 #if defined(HAVE_POSIX_ACLS)
6691 static NTSTATUS smb_set_posix_acl(connection_struct *conn,
6692 const char *pdata,
6693 int total_data,
6694 files_struct *fsp,
6695 const struct smb_filename *smb_fname)
6697 uint16 posix_acl_version;
6698 uint16 num_file_acls;
6699 uint16 num_def_acls;
6700 bool valid_file_acls = True;
6701 bool valid_def_acls = True;
6703 if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
6704 return NT_STATUS_INVALID_PARAMETER;
6706 posix_acl_version = SVAL(pdata,0);
6707 num_file_acls = SVAL(pdata,2);
6708 num_def_acls = SVAL(pdata,4);
6710 if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
6711 valid_file_acls = False;
6712 num_file_acls = 0;
6715 if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
6716 valid_def_acls = False;
6717 num_def_acls = 0;
6720 if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
6721 return NT_STATUS_INVALID_PARAMETER;
6724 if (total_data < SMB_POSIX_ACL_HEADER_SIZE +
6725 (num_file_acls+num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE) {
6726 return NT_STATUS_INVALID_PARAMETER;
6729 DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
6730 smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
6731 (unsigned int)num_file_acls,
6732 (unsigned int)num_def_acls));
6734 if (valid_file_acls && !set_unix_posix_acl(conn, fsp,
6735 smb_fname->base_name, num_file_acls,
6736 pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
6737 return map_nt_error_from_unix(errno);
6740 if (valid_def_acls && !set_unix_posix_default_acl(conn,
6741 smb_fname->base_name, &smb_fname->st, num_def_acls,
6742 pdata + SMB_POSIX_ACL_HEADER_SIZE +
6743 (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) {
6744 return map_nt_error_from_unix(errno);
6746 return NT_STATUS_OK;
6748 #endif
6750 /****************************************************************************
6751 Deal with SMB_SET_POSIX_LOCK.
6752 ****************************************************************************/
6754 static NTSTATUS smb_set_posix_lock(connection_struct *conn,
6755 struct smb_request *req,
6756 const char *pdata,
6757 int total_data,
6758 files_struct *fsp)
6760 uint64_t count;
6761 uint64_t offset;
6762 uint64_t smblctx;
6763 bool blocking_lock = False;
6764 enum brl_type lock_type;
6766 NTSTATUS status = NT_STATUS_OK;
6768 if (fsp == NULL || fsp->fh->fd == -1) {
6769 return NT_STATUS_INVALID_HANDLE;
6772 if (total_data != POSIX_LOCK_DATA_SIZE) {
6773 return NT_STATUS_INVALID_PARAMETER;
6776 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
6777 case POSIX_LOCK_TYPE_READ:
6778 lock_type = READ_LOCK;
6779 break;
6780 case POSIX_LOCK_TYPE_WRITE:
6781 /* Return the right POSIX-mappable error code for files opened read-only. */
6782 if (!fsp->can_write) {
6783 return NT_STATUS_INVALID_HANDLE;
6785 lock_type = WRITE_LOCK;
6786 break;
6787 case POSIX_LOCK_TYPE_UNLOCK:
6788 lock_type = UNLOCK_LOCK;
6789 break;
6790 default:
6791 return NT_STATUS_INVALID_PARAMETER;
6794 if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
6795 blocking_lock = False;
6796 } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
6797 blocking_lock = True;
6798 } else {
6799 return NT_STATUS_INVALID_PARAMETER;
6802 if (!lp_blocking_locks(SNUM(conn))) {
6803 blocking_lock = False;
6806 smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
6807 offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
6808 ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
6809 count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
6810 ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
6812 DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u,"
6813 "smblctx = %llu, count = %.0f, offset = %.0f\n",
6814 fsp_str_dbg(fsp),
6815 (unsigned int)lock_type,
6816 (unsigned long long)smblctx,
6817 (double)count,
6818 (double)offset ));
6820 if (lock_type == UNLOCK_LOCK) {
6821 status = do_unlock(req->sconn->msg_ctx,
6822 fsp,
6823 smblctx,
6824 count,
6825 offset,
6826 POSIX_LOCK);
6827 } else {
6828 uint64_t block_smblctx;
6830 struct byte_range_lock *br_lck = do_lock(req->sconn->msg_ctx,
6831 fsp,
6832 smblctx,
6833 count,
6834 offset,
6835 lock_type,
6836 POSIX_LOCK,
6837 blocking_lock,
6838 &status,
6839 &block_smblctx);
6841 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
6843 * A blocking lock was requested. Package up
6844 * this smb into a queued request and push it
6845 * onto the blocking lock queue.
6847 if(push_blocking_lock_request(br_lck,
6848 req,
6849 fsp,
6850 -1, /* infinite timeout. */
6852 smblctx,
6853 lock_type,
6854 POSIX_LOCK,
6855 offset,
6856 count,
6857 block_smblctx)) {
6858 TALLOC_FREE(br_lck);
6859 return status;
6862 TALLOC_FREE(br_lck);
6865 return status;
6868 /****************************************************************************
6869 Deal with SMB_SET_FILE_BASIC_INFO.
6870 ****************************************************************************/
6872 static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
6873 const char *pdata,
6874 int total_data,
6875 files_struct *fsp,
6876 const struct smb_filename *smb_fname)
6878 /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
6879 struct smb_file_time ft;
6880 uint32 dosmode = 0;
6881 NTSTATUS status = NT_STATUS_OK;
6883 ZERO_STRUCT(ft);
6885 if (total_data < 36) {
6886 return NT_STATUS_INVALID_PARAMETER;
6889 status = check_access(conn, fsp, smb_fname, FILE_WRITE_ATTRIBUTES);
6890 if (!NT_STATUS_IS_OK(status)) {
6891 return status;
6894 /* Set the attributes */
6895 dosmode = IVAL(pdata,32);
6896 status = smb_set_file_dosmode(conn, smb_fname, dosmode);
6897 if (!NT_STATUS_IS_OK(status)) {
6898 return status;
6901 /* create time */
6902 ft.create_time = interpret_long_date(pdata);
6904 /* access time */
6905 ft.atime = interpret_long_date(pdata+8);
6907 /* write time. */
6908 ft.mtime = interpret_long_date(pdata+16);
6910 /* change time. */
6911 ft.ctime = interpret_long_date(pdata+24);
6913 DEBUG(10, ("smb_set_file_basic_info: file %s\n",
6914 smb_fname_str_dbg(smb_fname)));
6916 return smb_set_file_time(conn, fsp, smb_fname, &ft,
6917 true);
6920 /****************************************************************************
6921 Deal with SMB_INFO_STANDARD.
6922 ****************************************************************************/
6924 static NTSTATUS smb_set_info_standard(connection_struct *conn,
6925 const char *pdata,
6926 int total_data,
6927 files_struct *fsp,
6928 const struct smb_filename *smb_fname)
6930 NTSTATUS status;
6931 struct smb_file_time ft;
6933 ZERO_STRUCT(ft);
6935 if (total_data < 12) {
6936 return NT_STATUS_INVALID_PARAMETER;
6939 /* create time */
6940 ft.create_time = convert_time_t_to_timespec(srv_make_unix_date2(pdata));
6941 /* access time */
6942 ft.atime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+4));
6943 /* write time */
6944 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+8));
6946 DEBUG(10,("smb_set_info_standard: file %s\n",
6947 smb_fname_str_dbg(smb_fname)));
6949 status = check_access(conn, fsp, smb_fname, FILE_WRITE_ATTRIBUTES);
6950 if (!NT_STATUS_IS_OK(status)) {
6951 return status;
6954 return smb_set_file_time(conn,
6955 fsp,
6956 smb_fname,
6957 &ft,
6958 true);
6961 /****************************************************************************
6962 Deal with SMB_SET_FILE_ALLOCATION_INFO.
6963 ****************************************************************************/
6965 static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
6966 struct smb_request *req,
6967 const char *pdata,
6968 int total_data,
6969 files_struct *fsp,
6970 struct smb_filename *smb_fname)
6972 uint64_t allocation_size = 0;
6973 NTSTATUS status = NT_STATUS_OK;
6974 files_struct *new_fsp = NULL;
6976 if (!VALID_STAT(smb_fname->st)) {
6977 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6980 if (total_data < 8) {
6981 return NT_STATUS_INVALID_PARAMETER;
6984 allocation_size = (uint64_t)IVAL(pdata,0);
6985 allocation_size |= (((uint64_t)IVAL(pdata,4)) << 32);
6986 DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for "
6987 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
6988 (double)allocation_size));
6990 if (allocation_size) {
6991 allocation_size = smb_roundup(conn, allocation_size);
6994 DEBUG(10,("smb_set_file_allocation_info: file %s : setting new "
6995 "allocation size to %.0f\n", smb_fname_str_dbg(smb_fname),
6996 (double)allocation_size));
6998 if (fsp && fsp->fh->fd != -1) {
6999 /* Open file handle. */
7000 if (!(fsp->access_mask & FILE_WRITE_DATA)) {
7001 return NT_STATUS_ACCESS_DENIED;
7004 /* Only change if needed. */
7005 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
7006 if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
7007 return map_nt_error_from_unix(errno);
7010 /* But always update the time. */
7012 * This is equivalent to a write. Ensure it's seen immediately
7013 * if there are no pending writes.
7015 trigger_write_time_update_immediate(fsp);
7016 return NT_STATUS_OK;
7019 /* Pathname or stat or directory file. */
7020 status = SMB_VFS_CREATE_FILE(
7021 conn, /* conn */
7022 req, /* req */
7023 0, /* root_dir_fid */
7024 smb_fname, /* fname */
7025 FILE_WRITE_DATA, /* access_mask */
7026 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7027 FILE_SHARE_DELETE),
7028 FILE_OPEN, /* create_disposition*/
7029 0, /* create_options */
7030 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
7031 0, /* oplock_request */
7032 NULL, /* lease */
7033 0, /* allocation_size */
7034 0, /* private_flags */
7035 NULL, /* sd */
7036 NULL, /* ea_list */
7037 &new_fsp, /* result */
7038 NULL, /* pinfo */
7039 NULL, NULL); /* create context */
7041 if (!NT_STATUS_IS_OK(status)) {
7042 /* NB. We check for open_was_deferred in the caller. */
7043 return status;
7046 /* Only change if needed. */
7047 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
7048 if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) {
7049 status = map_nt_error_from_unix(errno);
7050 close_file(req, new_fsp, NORMAL_CLOSE);
7051 return status;
7055 /* Changing the allocation size should set the last mod time. */
7057 * This is equivalent to a write. Ensure it's seen immediately
7058 * if there are no pending writes.
7060 trigger_write_time_update_immediate(new_fsp);
7061 close_file(req, new_fsp, NORMAL_CLOSE);
7062 return NT_STATUS_OK;
7065 /****************************************************************************
7066 Deal with SMB_SET_FILE_END_OF_FILE_INFO.
7067 ****************************************************************************/
7069 static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
7070 struct smb_request *req,
7071 const char *pdata,
7072 int total_data,
7073 files_struct *fsp,
7074 const struct smb_filename *smb_fname,
7075 bool fail_after_createfile)
7077 off_t size;
7079 if (total_data < 8) {
7080 return NT_STATUS_INVALID_PARAMETER;
7083 size = IVAL(pdata,0);
7084 size |= (((off_t)IVAL(pdata,4)) << 32);
7085 DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for "
7086 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
7087 (double)size));
7089 return smb_set_file_size(conn, req,
7090 fsp,
7091 smb_fname,
7092 &smb_fname->st,
7093 size,
7094 fail_after_createfile);
7097 /****************************************************************************
7098 Allow a UNIX info mknod.
7099 ****************************************************************************/
7101 static NTSTATUS smb_unix_mknod(connection_struct *conn,
7102 const char *pdata,
7103 int total_data,
7104 const struct smb_filename *smb_fname)
7106 uint32 file_type = IVAL(pdata,56);
7107 #if defined(HAVE_MAKEDEV)
7108 uint32 dev_major = IVAL(pdata,60);
7109 uint32 dev_minor = IVAL(pdata,68);
7110 #endif
7111 SMB_DEV_T dev = (SMB_DEV_T)0;
7112 uint32 raw_unixmode = IVAL(pdata,84);
7113 NTSTATUS status;
7114 mode_t unixmode;
7116 if (total_data < 100) {
7117 return NT_STATUS_INVALID_PARAMETER;
7120 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
7121 PERM_NEW_FILE, &unixmode);
7122 if (!NT_STATUS_IS_OK(status)) {
7123 return status;
7126 #if defined(HAVE_MAKEDEV)
7127 dev = makedev(dev_major, dev_minor);
7128 #endif
7130 switch (file_type) {
7131 #if defined(S_IFIFO)
7132 case UNIX_TYPE_FIFO:
7133 unixmode |= S_IFIFO;
7134 break;
7135 #endif
7136 #if defined(S_IFSOCK)
7137 case UNIX_TYPE_SOCKET:
7138 unixmode |= S_IFSOCK;
7139 break;
7140 #endif
7141 #if defined(S_IFCHR)
7142 case UNIX_TYPE_CHARDEV:
7143 unixmode |= S_IFCHR;
7144 break;
7145 #endif
7146 #if defined(S_IFBLK)
7147 case UNIX_TYPE_BLKDEV:
7148 unixmode |= S_IFBLK;
7149 break;
7150 #endif
7151 default:
7152 return NT_STATUS_INVALID_PARAMETER;
7155 DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
7156 "%.0f mode 0%o for file %s\n", (double)dev,
7157 (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
7159 /* Ok - do the mknod. */
7160 if (SMB_VFS_MKNOD(conn, smb_fname->base_name, unixmode, dev) != 0) {
7161 return map_nt_error_from_unix(errno);
7164 /* If any of the other "set" calls fail we
7165 * don't want to end up with a half-constructed mknod.
7168 if (lp_inherit_permissions(SNUM(conn))) {
7169 char *parent;
7170 if (!parent_dirname(talloc_tos(), smb_fname->base_name,
7171 &parent, NULL)) {
7172 return NT_STATUS_NO_MEMORY;
7174 inherit_access_posix_acl(conn, parent, smb_fname->base_name,
7175 unixmode);
7176 TALLOC_FREE(parent);
7179 return NT_STATUS_OK;
7182 /****************************************************************************
7183 Deal with SMB_SET_FILE_UNIX_BASIC.
7184 ****************************************************************************/
7186 static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
7187 struct smb_request *req,
7188 const char *pdata,
7189 int total_data,
7190 files_struct *fsp,
7191 const struct smb_filename *smb_fname)
7193 struct smb_file_time ft;
7194 uint32 raw_unixmode;
7195 mode_t unixmode;
7196 off_t size = 0;
7197 uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
7198 gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
7199 NTSTATUS status = NT_STATUS_OK;
7200 bool delete_on_fail = False;
7201 enum perm_type ptype;
7202 files_struct *all_fsps = NULL;
7203 bool modify_mtime = true;
7204 struct file_id id;
7205 struct smb_filename *smb_fname_tmp = NULL;
7206 SMB_STRUCT_STAT sbuf;
7208 ZERO_STRUCT(ft);
7210 if (total_data < 100) {
7211 return NT_STATUS_INVALID_PARAMETER;
7214 if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
7215 IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
7216 size=IVAL(pdata,0); /* first 8 Bytes are size */
7217 size |= (((off_t)IVAL(pdata,4)) << 32);
7220 ft.atime = interpret_long_date(pdata+24); /* access_time */
7221 ft.mtime = interpret_long_date(pdata+32); /* modification_time */
7222 set_owner = (uid_t)IVAL(pdata,40);
7223 set_grp = (gid_t)IVAL(pdata,48);
7224 raw_unixmode = IVAL(pdata,84);
7226 if (VALID_STAT(smb_fname->st)) {
7227 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
7228 ptype = PERM_EXISTING_DIR;
7229 } else {
7230 ptype = PERM_EXISTING_FILE;
7232 } else {
7233 ptype = PERM_NEW_FILE;
7236 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
7237 ptype, &unixmode);
7238 if (!NT_STATUS_IS_OK(status)) {
7239 return status;
7242 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
7243 "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
7244 smb_fname_str_dbg(smb_fname), (double)size,
7245 (unsigned int)set_owner, (unsigned int)set_grp,
7246 (int)raw_unixmode));
7248 sbuf = smb_fname->st;
7250 if (!VALID_STAT(sbuf)) {
7252 * The only valid use of this is to create character and block
7253 * devices, and named pipes. This is deprecated (IMHO) and
7254 * a new info level should be used for mknod. JRA.
7257 status = smb_unix_mknod(conn,
7258 pdata,
7259 total_data,
7260 smb_fname);
7261 if (!NT_STATUS_IS_OK(status)) {
7262 return status;
7265 smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
7266 if (smb_fname_tmp == NULL) {
7267 return NT_STATUS_NO_MEMORY;
7270 if (SMB_VFS_STAT(conn, smb_fname_tmp) != 0) {
7271 status = map_nt_error_from_unix(errno);
7272 TALLOC_FREE(smb_fname_tmp);
7273 SMB_VFS_UNLINK(conn, smb_fname);
7274 return status;
7277 sbuf = smb_fname_tmp->st;
7278 smb_fname = smb_fname_tmp;
7280 /* Ensure we don't try and change anything else. */
7281 raw_unixmode = SMB_MODE_NO_CHANGE;
7282 size = get_file_size_stat(&sbuf);
7283 ft.atime = sbuf.st_ex_atime;
7284 ft.mtime = sbuf.st_ex_mtime;
7286 * We continue here as we might want to change the
7287 * owner uid/gid.
7289 delete_on_fail = True;
7292 #if 1
7293 /* Horrible backwards compatibility hack as an old server bug
7294 * allowed a CIFS client bug to remain unnoticed :-(. JRA.
7295 * */
7297 if (!size) {
7298 size = get_file_size_stat(&sbuf);
7300 #endif
7303 * Deal with the UNIX specific mode set.
7306 if (raw_unixmode != SMB_MODE_NO_CHANGE) {
7307 int ret;
7309 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
7310 "setting mode 0%o for file %s\n",
7311 (unsigned int)unixmode,
7312 smb_fname_str_dbg(smb_fname)));
7313 if (fsp && fsp->fh->fd != -1) {
7314 ret = SMB_VFS_FCHMOD(fsp, unixmode);
7315 } else {
7316 ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
7318 if (ret != 0) {
7319 return map_nt_error_from_unix(errno);
7324 * Deal with the UNIX specific uid set.
7327 if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
7328 (sbuf.st_ex_uid != set_owner)) {
7329 int ret;
7331 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
7332 "changing owner %u for path %s\n",
7333 (unsigned int)set_owner,
7334 smb_fname_str_dbg(smb_fname)));
7336 if (fsp && fsp->fh->fd != -1) {
7337 ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
7338 } else {
7340 * UNIX extensions calls must always operate
7341 * on symlinks.
7343 ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name,
7344 set_owner, (gid_t)-1);
7347 if (ret != 0) {
7348 status = map_nt_error_from_unix(errno);
7349 if (delete_on_fail) {
7350 SMB_VFS_UNLINK(conn, smb_fname);
7352 return status;
7357 * Deal with the UNIX specific gid set.
7360 if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
7361 (sbuf.st_ex_gid != set_grp)) {
7362 int ret;
7364 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
7365 "changing group %u for file %s\n",
7366 (unsigned int)set_owner,
7367 smb_fname_str_dbg(smb_fname)));
7368 if (fsp && fsp->fh->fd != -1) {
7369 ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
7370 } else {
7372 * UNIX extensions calls must always operate
7373 * on symlinks.
7375 ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, (uid_t)-1,
7376 set_grp);
7378 if (ret != 0) {
7379 status = map_nt_error_from_unix(errno);
7380 if (delete_on_fail) {
7381 SMB_VFS_UNLINK(conn, smb_fname);
7383 return status;
7387 /* Deal with any size changes. */
7389 status = smb_set_file_size(conn, req,
7390 fsp,
7391 smb_fname,
7392 &sbuf,
7393 size,
7394 false);
7395 if (!NT_STATUS_IS_OK(status)) {
7396 return status;
7399 /* Deal with any time changes. */
7400 if (null_timespec(ft.mtime) && null_timespec(ft.atime)) {
7401 /* No change, don't cancel anything. */
7402 return status;
7405 id = vfs_file_id_from_sbuf(conn, &sbuf);
7406 for(all_fsps = file_find_di_first(conn->sconn, id); all_fsps;
7407 all_fsps = file_find_di_next(all_fsps)) {
7409 * We're setting the time explicitly for UNIX.
7410 * Cancel any pending changes over all handles.
7412 all_fsps->update_write_time_on_close = false;
7413 TALLOC_FREE(all_fsps->update_write_time_event);
7417 * Override the "setting_write_time"
7418 * parameter here as it almost does what
7419 * we need. Just remember if we modified
7420 * mtime and send the notify ourselves.
7422 if (null_timespec(ft.mtime)) {
7423 modify_mtime = false;
7426 status = smb_set_file_time(conn,
7427 fsp,
7428 smb_fname,
7429 &ft,
7430 false);
7431 if (modify_mtime) {
7432 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
7433 FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
7435 return status;
7438 /****************************************************************************
7439 Deal with SMB_SET_FILE_UNIX_INFO2.
7440 ****************************************************************************/
7442 static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
7443 struct smb_request *req,
7444 const char *pdata,
7445 int total_data,
7446 files_struct *fsp,
7447 const struct smb_filename *smb_fname)
7449 NTSTATUS status;
7450 uint32 smb_fflags;
7451 uint32 smb_fmask;
7453 if (total_data < 116) {
7454 return NT_STATUS_INVALID_PARAMETER;
7457 /* Start by setting all the fields that are common between UNIX_BASIC
7458 * and UNIX_INFO2.
7460 status = smb_set_file_unix_basic(conn, req, pdata, total_data,
7461 fsp, smb_fname);
7462 if (!NT_STATUS_IS_OK(status)) {
7463 return status;
7466 smb_fflags = IVAL(pdata, 108);
7467 smb_fmask = IVAL(pdata, 112);
7469 /* NB: We should only attempt to alter the file flags if the client
7470 * sends a non-zero mask.
7472 if (smb_fmask != 0) {
7473 int stat_fflags = 0;
7475 if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
7476 smb_fmask, &stat_fflags)) {
7477 /* Client asked to alter a flag we don't understand. */
7478 return NT_STATUS_INVALID_PARAMETER;
7481 if (fsp && fsp->fh->fd != -1) {
7482 /* XXX: we should be using SMB_VFS_FCHFLAGS here. */
7483 return NT_STATUS_NOT_SUPPORTED;
7484 } else {
7485 if (SMB_VFS_CHFLAGS(conn, smb_fname->base_name,
7486 stat_fflags) != 0) {
7487 return map_nt_error_from_unix(errno);
7492 /* XXX: need to add support for changing the create_time here. You
7493 * can do this for paths on Darwin with setattrlist(2). The right way
7494 * to hook this up is probably by extending the VFS utimes interface.
7497 return NT_STATUS_OK;
7500 /****************************************************************************
7501 Create a directory with POSIX semantics.
7502 ****************************************************************************/
7504 static NTSTATUS smb_posix_mkdir(connection_struct *conn,
7505 struct smb_request *req,
7506 char **ppdata,
7507 int total_data,
7508 struct smb_filename *smb_fname,
7509 int *pdata_return_size)
7511 NTSTATUS status = NT_STATUS_OK;
7512 uint32 raw_unixmode = 0;
7513 uint32 mod_unixmode = 0;
7514 mode_t unixmode = (mode_t)0;
7515 files_struct *fsp = NULL;
7516 uint16 info_level_return = 0;
7517 int info;
7518 char *pdata = *ppdata;
7520 if (total_data < 18) {
7521 return NT_STATUS_INVALID_PARAMETER;
7524 raw_unixmode = IVAL(pdata,8);
7525 /* Next 4 bytes are not yet defined. */
7527 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
7528 PERM_NEW_DIR, &unixmode);
7529 if (!NT_STATUS_IS_OK(status)) {
7530 return status;
7533 mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
7535 DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
7536 smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
7538 status = SMB_VFS_CREATE_FILE(
7539 conn, /* conn */
7540 req, /* req */
7541 0, /* root_dir_fid */
7542 smb_fname, /* fname */
7543 FILE_READ_ATTRIBUTES, /* access_mask */
7544 FILE_SHARE_NONE, /* share_access */
7545 FILE_CREATE, /* create_disposition*/
7546 FILE_DIRECTORY_FILE, /* create_options */
7547 mod_unixmode, /* file_attributes */
7548 0, /* oplock_request */
7549 NULL, /* lease */
7550 0, /* allocation_size */
7551 0, /* private_flags */
7552 NULL, /* sd */
7553 NULL, /* ea_list */
7554 &fsp, /* result */
7555 &info, /* pinfo */
7556 NULL, NULL); /* create context */
7558 if (NT_STATUS_IS_OK(status)) {
7559 close_file(req, fsp, NORMAL_CLOSE);
7562 info_level_return = SVAL(pdata,16);
7564 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
7565 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
7566 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
7567 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
7568 } else {
7569 *pdata_return_size = 12;
7572 /* Realloc the data size */
7573 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
7574 if (*ppdata == NULL) {
7575 *pdata_return_size = 0;
7576 return NT_STATUS_NO_MEMORY;
7578 pdata = *ppdata;
7580 SSVAL(pdata,0,NO_OPLOCK_RETURN);
7581 SSVAL(pdata,2,0); /* No fnum. */
7582 SIVAL(pdata,4,info); /* Was directory created. */
7584 switch (info_level_return) {
7585 case SMB_QUERY_FILE_UNIX_BASIC:
7586 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
7587 SSVAL(pdata,10,0); /* Padding. */
7588 store_file_unix_basic(conn, pdata + 12, fsp,
7589 &smb_fname->st);
7590 break;
7591 case SMB_QUERY_FILE_UNIX_INFO2:
7592 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
7593 SSVAL(pdata,10,0); /* Padding. */
7594 store_file_unix_basic_info2(conn, pdata + 12, fsp,
7595 &smb_fname->st);
7596 break;
7597 default:
7598 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
7599 SSVAL(pdata,10,0); /* Padding. */
7600 break;
7603 return status;
7606 /****************************************************************************
7607 Open/Create a file with POSIX semantics.
7608 ****************************************************************************/
7610 #define SMB_O_RDONLY_MAPPING (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
7611 #define SMB_O_WRONLY_MAPPING (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA)
7613 static NTSTATUS smb_posix_open(connection_struct *conn,
7614 struct smb_request *req,
7615 char **ppdata,
7616 int total_data,
7617 struct smb_filename *smb_fname,
7618 int *pdata_return_size)
7620 bool extended_oplock_granted = False;
7621 char *pdata = *ppdata;
7622 uint32 flags = 0;
7623 uint32 wire_open_mode = 0;
7624 uint32 raw_unixmode = 0;
7625 uint32 mod_unixmode = 0;
7626 uint32 create_disp = 0;
7627 uint32 access_mask = 0;
7628 uint32 create_options = FILE_NON_DIRECTORY_FILE;
7629 NTSTATUS status = NT_STATUS_OK;
7630 mode_t unixmode = (mode_t)0;
7631 files_struct *fsp = NULL;
7632 int oplock_request = 0;
7633 int info = 0;
7634 uint16 info_level_return = 0;
7636 if (total_data < 18) {
7637 return NT_STATUS_INVALID_PARAMETER;
7640 flags = IVAL(pdata,0);
7641 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
7642 if (oplock_request) {
7643 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
7646 wire_open_mode = IVAL(pdata,4);
7648 if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
7649 return smb_posix_mkdir(conn, req,
7650 ppdata,
7651 total_data,
7652 smb_fname,
7653 pdata_return_size);
7656 switch (wire_open_mode & SMB_ACCMODE) {
7657 case SMB_O_RDONLY:
7658 access_mask = SMB_O_RDONLY_MAPPING;
7659 break;
7660 case SMB_O_WRONLY:
7661 access_mask = SMB_O_WRONLY_MAPPING;
7662 break;
7663 case SMB_O_RDWR:
7664 access_mask = (SMB_O_RDONLY_MAPPING|
7665 SMB_O_WRONLY_MAPPING);
7666 break;
7667 default:
7668 DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
7669 (unsigned int)wire_open_mode ));
7670 return NT_STATUS_INVALID_PARAMETER;
7673 wire_open_mode &= ~SMB_ACCMODE;
7675 /* First take care of O_CREAT|O_EXCL interactions. */
7676 switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
7677 case (SMB_O_CREAT | SMB_O_EXCL):
7678 /* File exists fail. File not exist create. */
7679 create_disp = FILE_CREATE;
7680 break;
7681 case SMB_O_CREAT:
7682 /* File exists open. File not exist create. */
7683 create_disp = FILE_OPEN_IF;
7684 break;
7685 case SMB_O_EXCL:
7686 /* O_EXCL on its own without O_CREAT is undefined.
7687 We deliberately ignore it as some versions of
7688 Linux CIFSFS can send a bare O_EXCL on the
7689 wire which other filesystems in the kernel
7690 ignore. See bug 9519 for details. */
7692 /* Fallthrough. */
7694 case 0:
7695 /* File exists open. File not exist fail. */
7696 create_disp = FILE_OPEN;
7697 break;
7698 default:
7699 DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
7700 (unsigned int)wire_open_mode ));
7701 return NT_STATUS_INVALID_PARAMETER;
7704 /* Next factor in the effects of O_TRUNC. */
7705 wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);
7707 if (wire_open_mode & SMB_O_TRUNC) {
7708 switch (create_disp) {
7709 case FILE_CREATE:
7710 /* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
7711 /* Leave create_disp alone as
7712 (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
7714 /* File exists fail. File not exist create. */
7715 break;
7716 case FILE_OPEN_IF:
7717 /* SMB_O_CREAT | SMB_O_TRUNC */
7718 /* File exists overwrite. File not exist create. */
7719 create_disp = FILE_OVERWRITE_IF;
7720 break;
7721 case FILE_OPEN:
7722 /* SMB_O_TRUNC */
7723 /* File exists overwrite. File not exist fail. */
7724 create_disp = FILE_OVERWRITE;
7725 break;
7726 default:
7727 /* Cannot get here. */
7728 smb_panic("smb_posix_open: logic error");
7729 return NT_STATUS_INVALID_PARAMETER;
7733 raw_unixmode = IVAL(pdata,8);
7734 /* Next 4 bytes are not yet defined. */
7736 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
7737 (VALID_STAT(smb_fname->st) ?
7738 PERM_EXISTING_FILE : PERM_NEW_FILE),
7739 &unixmode);
7741 if (!NT_STATUS_IS_OK(status)) {
7742 return status;
7745 mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
7747 if (wire_open_mode & SMB_O_SYNC) {
7748 create_options |= FILE_WRITE_THROUGH;
7750 if (wire_open_mode & SMB_O_APPEND) {
7751 access_mask |= FILE_APPEND_DATA;
7753 if (wire_open_mode & SMB_O_DIRECT) {
7754 mod_unixmode |= FILE_FLAG_NO_BUFFERING;
7757 if ((wire_open_mode & SMB_O_DIRECTORY) ||
7758 VALID_STAT_OF_DIR(smb_fname->st)) {
7759 if (access_mask != SMB_O_RDONLY_MAPPING) {
7760 return NT_STATUS_FILE_IS_A_DIRECTORY;
7762 create_options &= ~FILE_NON_DIRECTORY_FILE;
7763 create_options |= FILE_DIRECTORY_FILE;
7766 DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
7767 smb_fname_str_dbg(smb_fname),
7768 (unsigned int)wire_open_mode,
7769 (unsigned int)unixmode ));
7771 status = SMB_VFS_CREATE_FILE(
7772 conn, /* conn */
7773 req, /* req */
7774 0, /* root_dir_fid */
7775 smb_fname, /* fname */
7776 access_mask, /* access_mask */
7777 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7778 FILE_SHARE_DELETE),
7779 create_disp, /* create_disposition*/
7780 create_options, /* create_options */
7781 mod_unixmode, /* file_attributes */
7782 oplock_request, /* oplock_request */
7783 NULL, /* lease */
7784 0, /* allocation_size */
7785 0, /* private_flags */
7786 NULL, /* sd */
7787 NULL, /* ea_list */
7788 &fsp, /* result */
7789 &info, /* pinfo */
7790 NULL, NULL); /* create context */
7792 if (!NT_STATUS_IS_OK(status)) {
7793 return status;
7796 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
7797 extended_oplock_granted = True;
7800 if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
7801 extended_oplock_granted = True;
7804 info_level_return = SVAL(pdata,16);
7806 /* Allocate the correct return size. */
7808 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
7809 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
7810 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
7811 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
7812 } else {
7813 *pdata_return_size = 12;
7816 /* Realloc the data size */
7817 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
7818 if (*ppdata == NULL) {
7819 close_file(req, fsp, ERROR_CLOSE);
7820 *pdata_return_size = 0;
7821 return NT_STATUS_NO_MEMORY;
7823 pdata = *ppdata;
7825 if (extended_oplock_granted) {
7826 if (flags & REQUEST_BATCH_OPLOCK) {
7827 SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
7828 } else {
7829 SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
7831 } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
7832 SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
7833 } else {
7834 SSVAL(pdata,0,NO_OPLOCK_RETURN);
7837 SSVAL(pdata,2,fsp->fnum);
7838 SIVAL(pdata,4,info); /* Was file created etc. */
7840 switch (info_level_return) {
7841 case SMB_QUERY_FILE_UNIX_BASIC:
7842 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
7843 SSVAL(pdata,10,0); /* padding. */
7844 store_file_unix_basic(conn, pdata + 12, fsp,
7845 &smb_fname->st);
7846 break;
7847 case SMB_QUERY_FILE_UNIX_INFO2:
7848 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
7849 SSVAL(pdata,10,0); /* padding. */
7850 store_file_unix_basic_info2(conn, pdata + 12, fsp,
7851 &smb_fname->st);
7852 break;
7853 default:
7854 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
7855 SSVAL(pdata,10,0); /* padding. */
7856 break;
7858 return NT_STATUS_OK;
7861 /****************************************************************************
7862 Delete a file with POSIX semantics.
7863 ****************************************************************************/
7865 static NTSTATUS smb_posix_unlink(connection_struct *conn,
7866 struct smb_request *req,
7867 const char *pdata,
7868 int total_data,
7869 struct smb_filename *smb_fname)
7871 NTSTATUS status = NT_STATUS_OK;
7872 files_struct *fsp = NULL;
7873 uint16 flags = 0;
7874 char del = 1;
7875 int info = 0;
7876 int create_options = 0;
7877 int i;
7878 struct share_mode_lock *lck = NULL;
7880 if (total_data < 2) {
7881 return NT_STATUS_INVALID_PARAMETER;
7884 flags = SVAL(pdata,0);
7886 if (!VALID_STAT(smb_fname->st)) {
7887 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
7890 if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
7891 !VALID_STAT_OF_DIR(smb_fname->st)) {
7892 return NT_STATUS_NOT_A_DIRECTORY;
7895 DEBUG(10,("smb_posix_unlink: %s %s\n",
7896 (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
7897 smb_fname_str_dbg(smb_fname)));
7899 if (VALID_STAT_OF_DIR(smb_fname->st)) {
7900 create_options |= FILE_DIRECTORY_FILE;
7903 status = SMB_VFS_CREATE_FILE(
7904 conn, /* conn */
7905 req, /* req */
7906 0, /* root_dir_fid */
7907 smb_fname, /* fname */
7908 DELETE_ACCESS, /* access_mask */
7909 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7910 FILE_SHARE_DELETE),
7911 FILE_OPEN, /* create_disposition*/
7912 create_options, /* create_options */
7913 FILE_FLAG_POSIX_SEMANTICS|0777, /* file_attributes */
7914 0, /* oplock_request */
7915 NULL, /* lease */
7916 0, /* allocation_size */
7917 0, /* private_flags */
7918 NULL, /* sd */
7919 NULL, /* ea_list */
7920 &fsp, /* result */
7921 &info, /* pinfo */
7922 NULL, NULL); /* create context */
7924 if (!NT_STATUS_IS_OK(status)) {
7925 return status;
7929 * Don't lie to client. If we can't really delete due to
7930 * non-POSIX opens return SHARING_VIOLATION.
7933 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
7934 if (lck == NULL) {
7935 DEBUG(0, ("smb_posix_unlink: Could not get share mode "
7936 "lock for file %s\n", fsp_str_dbg(fsp)));
7937 close_file(req, fsp, NORMAL_CLOSE);
7938 return NT_STATUS_INVALID_PARAMETER;
7942 * See if others still have the file open. If this is the case, then
7943 * don't delete. If all opens are POSIX delete we can set the delete
7944 * on close disposition.
7946 for (i=0; i<lck->data->num_share_modes; i++) {
7947 struct share_mode_entry *e = &lck->data->share_modes[i];
7948 if (is_valid_share_mode_entry(e)) {
7949 if (e->flags & SHARE_MODE_FLAG_POSIX_OPEN) {
7950 continue;
7952 if (share_mode_stale_pid(lck->data, i)) {
7953 continue;
7955 /* Fail with sharing violation. */
7956 TALLOC_FREE(lck);
7957 close_file(req, fsp, NORMAL_CLOSE);
7958 return NT_STATUS_SHARING_VIOLATION;
7963 * Set the delete on close.
7965 status = smb_set_file_disposition_info(conn,
7966 &del,
7968 fsp,
7969 smb_fname);
7971 TALLOC_FREE(lck);
7973 if (!NT_STATUS_IS_OK(status)) {
7974 close_file(req, fsp, NORMAL_CLOSE);
7975 return status;
7977 return close_file(req, fsp, NORMAL_CLOSE);
7980 NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
7981 struct smb_request *req,
7982 TALLOC_CTX *mem_ctx,
7983 uint16_t info_level,
7984 files_struct *fsp,
7985 struct smb_filename *smb_fname,
7986 char **ppdata, int total_data,
7987 int *ret_data_size)
7989 char *pdata = *ppdata;
7990 NTSTATUS status = NT_STATUS_OK;
7991 int data_return_size = 0;
7993 *ret_data_size = 0;
7995 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
7996 return NT_STATUS_INVALID_LEVEL;
7999 if (!CAN_WRITE(conn)) {
8000 /* Allow POSIX opens. The open path will deny
8001 * any non-readonly opens. */
8002 if (info_level != SMB_POSIX_PATH_OPEN) {
8003 return NT_STATUS_DOS(ERRSRV, ERRaccess);
8007 DEBUG(3,("smbd_do_setfilepathinfo: %s (%s) info_level=%d "
8008 "totdata=%d\n", smb_fname_str_dbg(smb_fname),
8009 fsp_fnum_dbg(fsp),
8010 info_level, total_data));
8012 switch (info_level) {
8014 case SMB_INFO_STANDARD:
8016 status = smb_set_info_standard(conn,
8017 pdata,
8018 total_data,
8019 fsp,
8020 smb_fname);
8021 break;
8024 case SMB_INFO_SET_EA:
8026 status = smb_info_set_ea(conn,
8027 pdata,
8028 total_data,
8029 fsp,
8030 smb_fname);
8031 break;
8034 case SMB_SET_FILE_BASIC_INFO:
8035 case SMB_FILE_BASIC_INFORMATION:
8037 status = smb_set_file_basic_info(conn,
8038 pdata,
8039 total_data,
8040 fsp,
8041 smb_fname);
8042 break;
8045 case SMB_FILE_ALLOCATION_INFORMATION:
8046 case SMB_SET_FILE_ALLOCATION_INFO:
8048 status = smb_set_file_allocation_info(conn, req,
8049 pdata,
8050 total_data,
8051 fsp,
8052 smb_fname);
8053 break;
8056 case SMB_FILE_END_OF_FILE_INFORMATION:
8057 case SMB_SET_FILE_END_OF_FILE_INFO:
8060 * XP/Win7 both fail after the createfile with
8061 * SMB_SET_FILE_END_OF_FILE_INFO but not
8062 * SMB_FILE_END_OF_FILE_INFORMATION (pass-through).
8063 * The level is known here, so pass it down
8064 * appropriately.
8066 bool should_fail =
8067 (info_level == SMB_SET_FILE_END_OF_FILE_INFO);
8069 status = smb_set_file_end_of_file_info(conn, req,
8070 pdata,
8071 total_data,
8072 fsp,
8073 smb_fname,
8074 should_fail);
8075 break;
8078 case SMB_FILE_DISPOSITION_INFORMATION:
8079 case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
8081 #if 0
8082 /* JRA - We used to just ignore this on a path ?
8083 * Shouldn't this be invalid level on a pathname
8084 * based call ?
8086 if (tran_call != TRANSACT2_SETFILEINFO) {
8087 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
8089 #endif
8090 status = smb_set_file_disposition_info(conn,
8091 pdata,
8092 total_data,
8093 fsp,
8094 smb_fname);
8095 break;
8098 case SMB_FILE_POSITION_INFORMATION:
8100 status = smb_file_position_information(conn,
8101 pdata,
8102 total_data,
8103 fsp);
8104 break;
8107 case SMB_FILE_FULL_EA_INFORMATION:
8109 status = smb_set_file_full_ea_info(conn,
8110 pdata,
8111 total_data,
8112 fsp);
8113 break;
8116 /* From tridge Samba4 :
8117 * MODE_INFORMATION in setfileinfo (I have no
8118 * idea what "mode information" on a file is - it takes a value of 0,
8119 * 2, 4 or 6. What could it be?).
8122 case SMB_FILE_MODE_INFORMATION:
8124 status = smb_file_mode_information(conn,
8125 pdata,
8126 total_data);
8127 break;
8131 * CIFS UNIX extensions.
8134 case SMB_SET_FILE_UNIX_BASIC:
8136 status = smb_set_file_unix_basic(conn, req,
8137 pdata,
8138 total_data,
8139 fsp,
8140 smb_fname);
8141 break;
8144 case SMB_SET_FILE_UNIX_INFO2:
8146 status = smb_set_file_unix_info2(conn, req,
8147 pdata,
8148 total_data,
8149 fsp,
8150 smb_fname);
8151 break;
8154 case SMB_SET_FILE_UNIX_LINK:
8156 if (fsp) {
8157 /* We must have a pathname for this. */
8158 return NT_STATUS_INVALID_LEVEL;
8160 status = smb_set_file_unix_link(conn, req, pdata,
8161 total_data, smb_fname);
8162 break;
8165 case SMB_SET_FILE_UNIX_HLINK:
8167 if (fsp) {
8168 /* We must have a pathname for this. */
8169 return NT_STATUS_INVALID_LEVEL;
8171 status = smb_set_file_unix_hlink(conn, req,
8172 pdata, total_data,
8173 smb_fname);
8174 break;
8177 case SMB_FILE_RENAME_INFORMATION:
8179 status = smb_file_rename_information(conn, req,
8180 pdata, total_data,
8181 fsp, smb_fname);
8182 break;
8185 case SMB2_FILE_RENAME_INFORMATION_INTERNAL:
8187 /* SMB2 rename information. */
8188 status = smb2_file_rename_information(conn, req,
8189 pdata, total_data,
8190 fsp, smb_fname);
8191 break;
8194 case SMB_FILE_LINK_INFORMATION:
8196 status = smb_file_link_information(conn, req,
8197 pdata, total_data,
8198 fsp, smb_fname);
8199 break;
8202 #if defined(HAVE_POSIX_ACLS)
8203 case SMB_SET_POSIX_ACL:
8205 status = smb_set_posix_acl(conn,
8206 pdata,
8207 total_data,
8208 fsp,
8209 smb_fname);
8210 break;
8212 #endif
8214 case SMB_SET_POSIX_LOCK:
8216 if (!fsp) {
8217 return NT_STATUS_INVALID_LEVEL;
8219 status = smb_set_posix_lock(conn, req,
8220 pdata, total_data, fsp);
8221 break;
8224 case SMB_POSIX_PATH_OPEN:
8226 if (fsp) {
8227 /* We must have a pathname for this. */
8228 return NT_STATUS_INVALID_LEVEL;
8231 status = smb_posix_open(conn, req,
8232 ppdata,
8233 total_data,
8234 smb_fname,
8235 &data_return_size);
8236 break;
8239 case SMB_POSIX_PATH_UNLINK:
8241 if (fsp) {
8242 /* We must have a pathname for this. */
8243 return NT_STATUS_INVALID_LEVEL;
8246 status = smb_posix_unlink(conn, req,
8247 pdata,
8248 total_data,
8249 smb_fname);
8250 break;
8253 default:
8254 return NT_STATUS_INVALID_LEVEL;
8257 if (!NT_STATUS_IS_OK(status)) {
8258 return status;
8261 *ret_data_size = data_return_size;
8262 return NT_STATUS_OK;
8265 /****************************************************************************
8266 Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname).
8267 ****************************************************************************/
8269 static void call_trans2setfilepathinfo(connection_struct *conn,
8270 struct smb_request *req,
8271 unsigned int tran_call,
8272 char **pparams, int total_params,
8273 char **ppdata, int total_data,
8274 unsigned int max_data_bytes)
8276 char *params = *pparams;
8277 char *pdata = *ppdata;
8278 uint16 info_level;
8279 struct smb_filename *smb_fname = NULL;
8280 files_struct *fsp = NULL;
8281 NTSTATUS status = NT_STATUS_OK;
8282 int data_return_size = 0;
8284 if (!params) {
8285 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8286 return;
8289 if (tran_call == TRANSACT2_SETFILEINFO) {
8290 if (total_params < 4) {
8291 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8292 return;
8295 fsp = file_fsp(req, SVAL(params,0));
8296 /* Basic check for non-null fsp. */
8297 if (!check_fsp_open(conn, req, fsp)) {
8298 return;
8300 info_level = SVAL(params,2);
8302 smb_fname = cp_smb_filename(talloc_tos(), fsp->fsp_name);
8303 if (smb_fname == NULL) {
8304 reply_nterror(req, NT_STATUS_NO_MEMORY);
8305 return;
8308 if(fsp->fh->fd == -1) {
8310 * This is actually a SETFILEINFO on a directory
8311 * handle (returned from an NT SMB). NT5.0 seems
8312 * to do this call. JRA.
8314 if (INFO_LEVEL_IS_UNIX(info_level)) {
8315 /* Always do lstat for UNIX calls. */
8316 if (SMB_VFS_LSTAT(conn, smb_fname)) {
8317 DEBUG(3,("call_trans2setfilepathinfo: "
8318 "SMB_VFS_LSTAT of %s failed "
8319 "(%s)\n",
8320 smb_fname_str_dbg(smb_fname),
8321 strerror(errno)));
8322 reply_nterror(req, map_nt_error_from_unix(errno));
8323 return;
8325 } else {
8326 if (SMB_VFS_STAT(conn, smb_fname) != 0) {
8327 DEBUG(3,("call_trans2setfilepathinfo: "
8328 "fileinfo of %s failed (%s)\n",
8329 smb_fname_str_dbg(smb_fname),
8330 strerror(errno)));
8331 reply_nterror(req, map_nt_error_from_unix(errno));
8332 return;
8335 } else if (fsp->print_file) {
8337 * Doing a DELETE_ON_CLOSE should cancel a print job.
8339 if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
8340 fsp->fh->private_options |= NTCREATEX_OPTIONS_PRIVATE_DELETE_ON_CLOSE;
8342 DEBUG(3,("call_trans2setfilepathinfo: "
8343 "Cancelling print job (%s)\n",
8344 fsp_str_dbg(fsp)));
8346 SSVAL(params,0,0);
8347 send_trans2_replies(conn, req, NT_STATUS_OK, params, 2,
8348 *ppdata, 0,
8349 max_data_bytes);
8350 return;
8351 } else {
8352 reply_nterror(req,
8353 NT_STATUS_OBJECT_PATH_NOT_FOUND);
8354 return;
8356 } else {
8358 * Original code - this is an open file.
8360 if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
8361 DEBUG(3,("call_trans2setfilepathinfo: fstat "
8362 "of %s failed (%s)\n", fsp_fnum_dbg(fsp),
8363 strerror(errno)));
8364 reply_nterror(req, map_nt_error_from_unix(errno));
8365 return;
8368 } else {
8369 char *fname = NULL;
8370 uint32_t ucf_flags = 0;
8372 /* set path info */
8373 if (total_params < 7) {
8374 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8375 return;
8378 info_level = SVAL(params,0);
8379 srvstr_get_path(req, params, req->flags2, &fname, &params[6],
8380 total_params - 6, STR_TERMINATE,
8381 &status);
8382 if (!NT_STATUS_IS_OK(status)) {
8383 reply_nterror(req, status);
8384 return;
8387 if (info_level == SMB_SET_FILE_UNIX_BASIC ||
8388 info_level == SMB_SET_FILE_UNIX_INFO2 ||
8389 info_level == SMB_FILE_RENAME_INFORMATION ||
8390 info_level == SMB_POSIX_PATH_UNLINK) {
8391 ucf_flags |= UCF_UNIX_NAME_LOOKUP;
8394 status = filename_convert(req, conn,
8395 req->flags2 & FLAGS2_DFS_PATHNAMES,
8396 fname,
8397 ucf_flags,
8398 NULL,
8399 &smb_fname);
8400 if (!NT_STATUS_IS_OK(status)) {
8401 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8402 reply_botherror(req,
8403 NT_STATUS_PATH_NOT_COVERED,
8404 ERRSRV, ERRbadpath);
8405 return;
8407 reply_nterror(req, status);
8408 return;
8411 if (INFO_LEVEL_IS_UNIX(info_level)) {
8413 * For CIFS UNIX extensions the target name may not exist.
8416 /* Always do lstat for UNIX calls. */
8417 SMB_VFS_LSTAT(conn, smb_fname);
8419 } else if (!VALID_STAT(smb_fname->st) &&
8420 SMB_VFS_STAT(conn, smb_fname)) {
8421 DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of "
8422 "%s failed (%s)\n",
8423 smb_fname_str_dbg(smb_fname),
8424 strerror(errno)));
8425 reply_nterror(req, map_nt_error_from_unix(errno));
8426 return;
8430 DEBUG(3,("call_trans2setfilepathinfo(%d) %s (%s) info_level=%d "
8431 "totdata=%d\n", tran_call, smb_fname_str_dbg(smb_fname),
8432 fsp_fnum_dbg(fsp),
8433 info_level,total_data));
8435 /* Realloc the parameter size */
8436 *pparams = (char *)SMB_REALLOC(*pparams,2);
8437 if (*pparams == NULL) {
8438 reply_nterror(req, NT_STATUS_NO_MEMORY);
8439 return;
8441 params = *pparams;
8443 SSVAL(params,0,0);
8445 status = smbd_do_setfilepathinfo(conn, req, req,
8446 info_level,
8447 fsp,
8448 smb_fname,
8449 ppdata, total_data,
8450 &data_return_size);
8451 if (!NT_STATUS_IS_OK(status)) {
8452 if (open_was_deferred(req->xconn, req->mid)) {
8453 /* We have re-scheduled this call. */
8454 return;
8456 if (blocking_lock_was_deferred_smb1(req->sconn, req->mid)) {
8457 /* We have re-scheduled this call. */
8458 return;
8460 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8461 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
8462 ERRSRV, ERRbadpath);
8463 return;
8465 if (info_level == SMB_POSIX_PATH_OPEN) {
8466 reply_openerror(req, status);
8467 return;
8471 * Invalid EA name needs to return 2 param bytes,
8472 * not a zero-length error packet.
8474 if (NT_STATUS_EQUAL(status, STATUS_INVALID_EA_NAME)) {
8475 send_trans2_replies(conn, req, status, params, 2, NULL, 0,
8476 max_data_bytes);
8477 } else {
8478 reply_nterror(req, status);
8480 return;
8483 send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, data_return_size,
8484 max_data_bytes);
8486 return;
8489 /****************************************************************************
8490 Reply to a TRANS2_MKDIR (make directory with extended attributes).
8491 ****************************************************************************/
8493 static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
8494 char **pparams, int total_params,
8495 char **ppdata, int total_data,
8496 unsigned int max_data_bytes)
8498 struct smb_filename *smb_dname = NULL;
8499 char *params = *pparams;
8500 char *pdata = *ppdata;
8501 char *directory = NULL;
8502 NTSTATUS status = NT_STATUS_OK;
8503 struct ea_list *ea_list = NULL;
8504 TALLOC_CTX *ctx = talloc_tos();
8506 if (!CAN_WRITE(conn)) {
8507 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8508 return;
8511 if (total_params < 5) {
8512 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8513 return;
8516 srvstr_get_path(ctx, params, req->flags2, &directory, &params[4],
8517 total_params - 4, STR_TERMINATE,
8518 &status);
8519 if (!NT_STATUS_IS_OK(status)) {
8520 reply_nterror(req, status);
8521 return;
8524 DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
8526 status = filename_convert(ctx,
8527 conn,
8528 req->flags2 & FLAGS2_DFS_PATHNAMES,
8529 directory,
8531 NULL,
8532 &smb_dname);
8534 if (!NT_STATUS_IS_OK(status)) {
8535 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
8536 reply_botherror(req,
8537 NT_STATUS_PATH_NOT_COVERED,
8538 ERRSRV, ERRbadpath);
8539 return;
8541 reply_nterror(req, status);
8542 return;
8546 * OS/2 workplace shell seems to send SET_EA requests of "null"
8547 * length (4 bytes containing IVAL 4).
8548 * They seem to have no effect. Bug #3212. JRA.
8551 if (total_data && (total_data != 4)) {
8552 /* Any data in this call is an EA list. */
8553 if (total_data < 10) {
8554 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8555 goto out;
8558 if (IVAL(pdata,0) > total_data) {
8559 DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
8560 IVAL(pdata,0), (unsigned int)total_data));
8561 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8562 goto out;
8565 ea_list = read_ea_list(talloc_tos(), pdata + 4,
8566 total_data - 4);
8567 if (!ea_list) {
8568 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8569 goto out;
8572 if (!lp_ea_support(SNUM(conn))) {
8573 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
8574 goto out;
8577 /* If total_data == 4 Windows doesn't care what values
8578 * are placed in that field, it just ignores them.
8579 * The System i QNTC IBM SMB client puts bad values here,
8580 * so ignore them. */
8582 status = create_directory(conn, req, smb_dname);
8584 if (!NT_STATUS_IS_OK(status)) {
8585 reply_nterror(req, status);
8586 goto out;
8589 /* Try and set any given EA. */
8590 if (ea_list) {
8591 status = set_ea(conn, NULL, smb_dname, ea_list);
8592 if (!NT_STATUS_IS_OK(status)) {
8593 reply_nterror(req, status);
8594 goto out;
8598 /* Realloc the parameter and data sizes */
8599 *pparams = (char *)SMB_REALLOC(*pparams,2);
8600 if(*pparams == NULL) {
8601 reply_nterror(req, NT_STATUS_NO_MEMORY);
8602 goto out;
8604 params = *pparams;
8606 SSVAL(params,0,0);
8608 send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, 0, max_data_bytes);
8610 out:
8611 TALLOC_FREE(smb_dname);
8612 return;
8615 /****************************************************************************
8616 Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
8617 We don't actually do this - we just send a null response.
8618 ****************************************************************************/
8620 static void call_trans2findnotifyfirst(connection_struct *conn,
8621 struct smb_request *req,
8622 char **pparams, int total_params,
8623 char **ppdata, int total_data,
8624 unsigned int max_data_bytes)
8626 char *params = *pparams;
8627 uint16 info_level;
8629 if (total_params < 6) {
8630 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8631 return;
8634 info_level = SVAL(params,4);
8635 DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
8637 switch (info_level) {
8638 case 1:
8639 case 2:
8640 break;
8641 default:
8642 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
8643 return;
8646 /* Realloc the parameter and data sizes */
8647 *pparams = (char *)SMB_REALLOC(*pparams,6);
8648 if (*pparams == NULL) {
8649 reply_nterror(req, NT_STATUS_NO_MEMORY);
8650 return;
8652 params = *pparams;
8654 SSVAL(params,0,fnf_handle);
8655 SSVAL(params,2,0); /* No changes */
8656 SSVAL(params,4,0); /* No EA errors */
8658 fnf_handle++;
8660 if(fnf_handle == 0)
8661 fnf_handle = 257;
8663 send_trans2_replies(conn, req, NT_STATUS_OK, params, 6, *ppdata, 0, max_data_bytes);
8665 return;
8668 /****************************************************************************
8669 Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
8670 changes). Currently this does nothing.
8671 ****************************************************************************/
8673 static void call_trans2findnotifynext(connection_struct *conn,
8674 struct smb_request *req,
8675 char **pparams, int total_params,
8676 char **ppdata, int total_data,
8677 unsigned int max_data_bytes)
8679 char *params = *pparams;
8681 DEBUG(3,("call_trans2findnotifynext\n"));
8683 /* Realloc the parameter and data sizes */
8684 *pparams = (char *)SMB_REALLOC(*pparams,4);
8685 if (*pparams == NULL) {
8686 reply_nterror(req, NT_STATUS_NO_MEMORY);
8687 return;
8689 params = *pparams;
8691 SSVAL(params,0,0); /* No changes */
8692 SSVAL(params,2,0); /* No EA errors */
8694 send_trans2_replies(conn, req, NT_STATUS_OK, params, 4, *ppdata, 0, max_data_bytes);
8696 return;
8699 /****************************************************************************
8700 Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
8701 ****************************************************************************/
8703 static void call_trans2getdfsreferral(connection_struct *conn,
8704 struct smb_request *req,
8705 char **pparams, int total_params,
8706 char **ppdata, int total_data,
8707 unsigned int max_data_bytes)
8709 char *params = *pparams;
8710 char *pathname = NULL;
8711 int reply_size = 0;
8712 int max_referral_level;
8713 NTSTATUS status = NT_STATUS_OK;
8714 TALLOC_CTX *ctx = talloc_tos();
8716 DEBUG(10,("call_trans2getdfsreferral\n"));
8718 if (total_params < 3) {
8719 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8720 return;
8723 max_referral_level = SVAL(params,0);
8725 if(!lp_host_msdfs()) {
8726 reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
8727 return;
8730 srvstr_pull_talloc(ctx, params, req->flags2, &pathname, &params[2],
8731 total_params - 2, STR_TERMINATE);
8732 if (!pathname) {
8733 reply_nterror(req, NT_STATUS_NOT_FOUND);
8734 return;
8736 if((reply_size = setup_dfs_referral(conn, pathname, max_referral_level,
8737 ppdata,&status)) < 0) {
8738 reply_nterror(req, status);
8739 return;
8742 SSVAL((discard_const_p(uint8_t, req->inbuf)), smb_flg2,
8743 SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
8744 send_trans2_replies(conn, req, NT_STATUS_OK, 0,0,*ppdata,reply_size, max_data_bytes);
8746 return;
8749 #define LMCAT_SPL 0x53
8750 #define LMFUNC_GETJOBID 0x60
8752 /****************************************************************************
8753 Reply to a TRANS2_IOCTL - used for OS/2 printing.
8754 ****************************************************************************/
8756 static void call_trans2ioctl(connection_struct *conn,
8757 struct smb_request *req,
8758 char **pparams, int total_params,
8759 char **ppdata, int total_data,
8760 unsigned int max_data_bytes)
8762 char *pdata = *ppdata;
8763 files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
8764 NTSTATUS status;
8765 size_t len = 0;
8767 /* check for an invalid fid before proceeding */
8769 if (!fsp) {
8770 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
8771 return;
8774 if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
8775 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
8776 *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
8777 if (*ppdata == NULL) {
8778 reply_nterror(req, NT_STATUS_NO_MEMORY);
8779 return;
8781 pdata = *ppdata;
8783 /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
8784 CAN ACCEPT THIS IN UNICODE. JRA. */
8786 /* Job number */
8787 SSVAL(pdata, 0, print_spool_rap_jobid(fsp->print_file));
8789 status = srvstr_push(pdata, req->flags2, pdata + 2,
8790 lp_netbios_name(), 15,
8791 STR_ASCII|STR_TERMINATE, &len); /* Our NetBIOS name */
8792 if (!NT_STATUS_IS_OK(status)) {
8793 reply_nterror(req, status);
8794 return;
8796 status = srvstr_push(pdata, req->flags2, pdata+18,
8797 lp_servicename(talloc_tos(), SNUM(conn)), 13,
8798 STR_ASCII|STR_TERMINATE, &len); /* Service name */
8799 if (!NT_STATUS_IS_OK(status)) {
8800 reply_nterror(req, status);
8801 return;
8803 send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32,
8804 max_data_bytes);
8805 return;
8808 DEBUG(2,("Unknown TRANS2_IOCTL\n"));
8809 reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
8812 /****************************************************************************
8813 Reply to a SMBfindclose (stop trans2 directory search).
8814 ****************************************************************************/
8816 void reply_findclose(struct smb_request *req)
8818 int dptr_num;
8819 struct smbd_server_connection *sconn = req->sconn;
8821 START_PROFILE(SMBfindclose);
8823 if (req->wct < 1) {
8824 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8825 END_PROFILE(SMBfindclose);
8826 return;
8829 dptr_num = SVALS(req->vwv+0, 0);
8831 DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
8833 dptr_close(sconn, &dptr_num);
8835 reply_outbuf(req, 0, 0);
8837 DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));
8839 END_PROFILE(SMBfindclose);
8840 return;
8843 /****************************************************************************
8844 Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search).
8845 ****************************************************************************/
8847 void reply_findnclose(struct smb_request *req)
8849 int dptr_num;
8851 START_PROFILE(SMBfindnclose);
8853 if (req->wct < 1) {
8854 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8855 END_PROFILE(SMBfindnclose);
8856 return;
8859 dptr_num = SVAL(req->vwv+0, 0);
8861 DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num));
8863 /* We never give out valid handles for a
8864 findnotifyfirst - so any dptr_num is ok here.
8865 Just ignore it. */
8867 reply_outbuf(req, 0, 0);
8869 DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));
8871 END_PROFILE(SMBfindnclose);
8872 return;
8875 static void handle_trans2(connection_struct *conn, struct smb_request *req,
8876 struct trans_state *state)
8878 if (get_Protocol() >= PROTOCOL_NT1) {
8879 req->flags2 |= 0x40; /* IS_LONG_NAME */
8880 SSVAL((discard_const_p(uint8_t, req->inbuf)),smb_flg2,req->flags2);
8883 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
8884 if (state->call != TRANSACT2_QFSINFO &&
8885 state->call != TRANSACT2_SETFSINFO) {
8886 DEBUG(0,("handle_trans2: encryption required "
8887 "with call 0x%x\n",
8888 (unsigned int)state->call));
8889 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8890 return;
8894 SMB_PERFCOUNT_SET_SUBOP(&req->pcd, state->call);
8896 /* Now we must call the relevant TRANS2 function */
8897 switch(state->call) {
8898 case TRANSACT2_OPEN:
8900 START_PROFILE(Trans2_open);
8901 call_trans2open(conn, req,
8902 &state->param, state->total_param,
8903 &state->data, state->total_data,
8904 state->max_data_return);
8905 END_PROFILE(Trans2_open);
8906 break;
8909 case TRANSACT2_FINDFIRST:
8911 START_PROFILE(Trans2_findfirst);
8912 call_trans2findfirst(conn, req,
8913 &state->param, state->total_param,
8914 &state->data, state->total_data,
8915 state->max_data_return);
8916 END_PROFILE(Trans2_findfirst);
8917 break;
8920 case TRANSACT2_FINDNEXT:
8922 START_PROFILE(Trans2_findnext);
8923 call_trans2findnext(conn, req,
8924 &state->param, state->total_param,
8925 &state->data, state->total_data,
8926 state->max_data_return);
8927 END_PROFILE(Trans2_findnext);
8928 break;
8931 case TRANSACT2_QFSINFO:
8933 START_PROFILE(Trans2_qfsinfo);
8934 call_trans2qfsinfo(conn, req,
8935 &state->param, state->total_param,
8936 &state->data, state->total_data,
8937 state->max_data_return);
8938 END_PROFILE(Trans2_qfsinfo);
8939 break;
8942 case TRANSACT2_SETFSINFO:
8944 START_PROFILE(Trans2_setfsinfo);
8945 call_trans2setfsinfo(conn, req,
8946 &state->param, state->total_param,
8947 &state->data, state->total_data,
8948 state->max_data_return);
8949 END_PROFILE(Trans2_setfsinfo);
8950 break;
8953 case TRANSACT2_QPATHINFO:
8954 case TRANSACT2_QFILEINFO:
8956 START_PROFILE(Trans2_qpathinfo);
8957 call_trans2qfilepathinfo(conn, req, state->call,
8958 &state->param, state->total_param,
8959 &state->data, state->total_data,
8960 state->max_data_return);
8961 END_PROFILE(Trans2_qpathinfo);
8962 break;
8965 case TRANSACT2_SETPATHINFO:
8966 case TRANSACT2_SETFILEINFO:
8968 START_PROFILE(Trans2_setpathinfo);
8969 call_trans2setfilepathinfo(conn, req, state->call,
8970 &state->param, state->total_param,
8971 &state->data, state->total_data,
8972 state->max_data_return);
8973 END_PROFILE(Trans2_setpathinfo);
8974 break;
8977 case TRANSACT2_FINDNOTIFYFIRST:
8979 START_PROFILE(Trans2_findnotifyfirst);
8980 call_trans2findnotifyfirst(conn, req,
8981 &state->param, state->total_param,
8982 &state->data, state->total_data,
8983 state->max_data_return);
8984 END_PROFILE(Trans2_findnotifyfirst);
8985 break;
8988 case TRANSACT2_FINDNOTIFYNEXT:
8990 START_PROFILE(Trans2_findnotifynext);
8991 call_trans2findnotifynext(conn, req,
8992 &state->param, state->total_param,
8993 &state->data, state->total_data,
8994 state->max_data_return);
8995 END_PROFILE(Trans2_findnotifynext);
8996 break;
8999 case TRANSACT2_MKDIR:
9001 START_PROFILE(Trans2_mkdir);
9002 call_trans2mkdir(conn, req,
9003 &state->param, state->total_param,
9004 &state->data, state->total_data,
9005 state->max_data_return);
9006 END_PROFILE(Trans2_mkdir);
9007 break;
9010 case TRANSACT2_GET_DFS_REFERRAL:
9012 START_PROFILE(Trans2_get_dfs_referral);
9013 call_trans2getdfsreferral(conn, req,
9014 &state->param, state->total_param,
9015 &state->data, state->total_data,
9016 state->max_data_return);
9017 END_PROFILE(Trans2_get_dfs_referral);
9018 break;
9021 case TRANSACT2_IOCTL:
9023 START_PROFILE(Trans2_ioctl);
9024 call_trans2ioctl(conn, req,
9025 &state->param, state->total_param,
9026 &state->data, state->total_data,
9027 state->max_data_return);
9028 END_PROFILE(Trans2_ioctl);
9029 break;
9032 default:
9033 /* Error in request */
9034 DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
9035 reply_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
9039 /****************************************************************************
9040 Reply to a SMBtrans2.
9041 ****************************************************************************/
9043 void reply_trans2(struct smb_request *req)
9045 connection_struct *conn = req->conn;
9046 unsigned int dsoff;
9047 unsigned int dscnt;
9048 unsigned int psoff;
9049 unsigned int pscnt;
9050 unsigned int tran_call;
9051 struct trans_state *state;
9052 NTSTATUS result;
9054 START_PROFILE(SMBtrans2);
9056 if (req->wct < 14) {
9057 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9058 END_PROFILE(SMBtrans2);
9059 return;
9062 dsoff = SVAL(req->vwv+12, 0);
9063 dscnt = SVAL(req->vwv+11, 0);
9064 psoff = SVAL(req->vwv+10, 0);
9065 pscnt = SVAL(req->vwv+9, 0);
9066 tran_call = SVAL(req->vwv+14, 0);
9068 result = allow_new_trans(conn->pending_trans, req->mid);
9069 if (!NT_STATUS_IS_OK(result)) {
9070 DEBUG(2, ("Got invalid trans2 request: %s\n",
9071 nt_errstr(result)));
9072 reply_nterror(req, result);
9073 END_PROFILE(SMBtrans2);
9074 return;
9077 if (IS_IPC(conn)) {
9078 switch (tran_call) {
9079 /* List the allowed trans2 calls on IPC$ */
9080 case TRANSACT2_OPEN:
9081 case TRANSACT2_GET_DFS_REFERRAL:
9082 case TRANSACT2_QFILEINFO:
9083 case TRANSACT2_QFSINFO:
9084 case TRANSACT2_SETFSINFO:
9085 break;
9086 default:
9087 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
9088 END_PROFILE(SMBtrans2);
9089 return;
9093 if ((state = talloc(conn, struct trans_state)) == NULL) {
9094 DEBUG(0, ("talloc failed\n"));
9095 reply_nterror(req, NT_STATUS_NO_MEMORY);
9096 END_PROFILE(SMBtrans2);
9097 return;
9100 state->cmd = SMBtrans2;
9102 state->mid = req->mid;
9103 state->vuid = req->vuid;
9104 state->setup_count = SVAL(req->vwv+13, 0);
9105 state->setup = NULL;
9106 state->total_param = SVAL(req->vwv+0, 0);
9107 state->param = NULL;
9108 state->total_data = SVAL(req->vwv+1, 0);
9109 state->data = NULL;
9110 state->max_param_return = SVAL(req->vwv+2, 0);
9111 state->max_data_return = SVAL(req->vwv+3, 0);
9112 state->max_setup_return = SVAL(req->vwv+4, 0);
9113 state->close_on_completion = BITSETW(req->vwv+5, 0);
9114 state->one_way = BITSETW(req->vwv+5, 1);
9116 state->call = tran_call;
9118 /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
9119 is so as a sanity check */
9120 if (state->setup_count != 1) {
9122 * Need to have rc=0 for ioctl to get job id for OS/2.
9123 * Network printing will fail if function is not successful.
9124 * Similar function in reply.c will be used if protocol
9125 * is LANMAN1.0 instead of LM1.2X002.
9126 * Until DosPrintSetJobInfo with PRJINFO3 is supported,
9127 * outbuf doesn't have to be set(only job id is used).
9129 if ( (state->setup_count == 4)
9130 && (tran_call == TRANSACT2_IOCTL)
9131 && (SVAL(req->vwv+16, 0) == LMCAT_SPL)
9132 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
9133 DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
9134 } else {
9135 DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
9136 DEBUG(2,("Transaction is %d\n",tran_call));
9137 TALLOC_FREE(state);
9138 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9139 END_PROFILE(SMBtrans2);
9140 return;
9144 if ((dscnt > state->total_data) || (pscnt > state->total_param))
9145 goto bad_param;
9147 if (state->total_data) {
9149 if (trans_oob(state->total_data, 0, dscnt)
9150 || trans_oob(smb_len(req->inbuf), dsoff, dscnt)) {
9151 goto bad_param;
9154 /* Can't use talloc here, the core routines do realloc on the
9155 * params and data. */
9156 state->data = (char *)SMB_MALLOC(state->total_data);
9157 if (state->data == NULL) {
9158 DEBUG(0,("reply_trans2: data malloc fail for %u "
9159 "bytes !\n", (unsigned int)state->total_data));
9160 TALLOC_FREE(state);
9161 reply_nterror(req, NT_STATUS_NO_MEMORY);
9162 END_PROFILE(SMBtrans2);
9163 return;
9166 memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
9169 if (state->total_param) {
9171 if (trans_oob(state->total_param, 0, pscnt)
9172 || trans_oob(smb_len(req->inbuf), psoff, pscnt)) {
9173 goto bad_param;
9176 /* Can't use talloc here, the core routines do realloc on the
9177 * params and data. */
9178 state->param = (char *)SMB_MALLOC(state->total_param);
9179 if (state->param == NULL) {
9180 DEBUG(0,("reply_trans: param malloc fail for %u "
9181 "bytes !\n", (unsigned int)state->total_param));
9182 SAFE_FREE(state->data);
9183 TALLOC_FREE(state);
9184 reply_nterror(req, NT_STATUS_NO_MEMORY);
9185 END_PROFILE(SMBtrans2);
9186 return;
9189 memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
9192 state->received_data = dscnt;
9193 state->received_param = pscnt;
9195 if ((state->received_param == state->total_param) &&
9196 (state->received_data == state->total_data)) {
9198 handle_trans2(conn, req, state);
9200 SAFE_FREE(state->data);
9201 SAFE_FREE(state->param);
9202 TALLOC_FREE(state);
9203 END_PROFILE(SMBtrans2);
9204 return;
9207 DLIST_ADD(conn->pending_trans, state);
9209 /* We need to send an interim response then receive the rest
9210 of the parameter/data bytes */
9211 reply_outbuf(req, 0, 0);
9212 show_msg((char *)req->outbuf);
9213 END_PROFILE(SMBtrans2);
9214 return;
9216 bad_param:
9218 DEBUG(0,("reply_trans2: invalid trans parameters\n"));
9219 SAFE_FREE(state->data);
9220 SAFE_FREE(state->param);
9221 TALLOC_FREE(state);
9222 END_PROFILE(SMBtrans2);
9223 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9227 /****************************************************************************
9228 Reply to a SMBtranss2
9229 ****************************************************************************/
9231 void reply_transs2(struct smb_request *req)
9233 connection_struct *conn = req->conn;
9234 unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
9235 struct trans_state *state;
9237 START_PROFILE(SMBtranss2);
9239 show_msg((const char *)req->inbuf);
9241 /* Windows clients expect all replies to
9242 a transact secondary (SMBtranss2 0x33)
9243 to have a command code of transact
9244 (SMBtrans2 0x32). See bug #8989
9245 and also [MS-CIFS] section 2.2.4.47.2
9246 for details.
9248 req->cmd = SMBtrans2;
9250 if (req->wct < 8) {
9251 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9252 END_PROFILE(SMBtranss2);
9253 return;
9256 for (state = conn->pending_trans; state != NULL;
9257 state = state->next) {
9258 if (state->mid == req->mid) {
9259 break;
9263 if ((state == NULL) || (state->cmd != SMBtrans2)) {
9264 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9265 END_PROFILE(SMBtranss2);
9266 return;
9269 /* Revise state->total_param and state->total_data in case they have
9270 changed downwards */
9272 if (SVAL(req->vwv+0, 0) < state->total_param)
9273 state->total_param = SVAL(req->vwv+0, 0);
9274 if (SVAL(req->vwv+1, 0) < state->total_data)
9275 state->total_data = SVAL(req->vwv+1, 0);
9277 pcnt = SVAL(req->vwv+2, 0);
9278 poff = SVAL(req->vwv+3, 0);
9279 pdisp = SVAL(req->vwv+4, 0);
9281 dcnt = SVAL(req->vwv+5, 0);
9282 doff = SVAL(req->vwv+6, 0);
9283 ddisp = SVAL(req->vwv+7, 0);
9285 state->received_param += pcnt;
9286 state->received_data += dcnt;
9288 if ((state->received_data > state->total_data) ||
9289 (state->received_param > state->total_param))
9290 goto bad_param;
9292 if (pcnt) {
9293 if (trans_oob(state->total_param, pdisp, pcnt)
9294 || trans_oob(smb_len(req->inbuf), poff, pcnt)) {
9295 goto bad_param;
9297 memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
9300 if (dcnt) {
9301 if (trans_oob(state->total_data, ddisp, dcnt)
9302 || trans_oob(smb_len(req->inbuf), doff, dcnt)) {
9303 goto bad_param;
9305 memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
9308 if ((state->received_param < state->total_param) ||
9309 (state->received_data < state->total_data)) {
9310 END_PROFILE(SMBtranss2);
9311 return;
9314 handle_trans2(conn, req, state);
9316 DLIST_REMOVE(conn->pending_trans, state);
9317 SAFE_FREE(state->data);
9318 SAFE_FREE(state->param);
9319 TALLOC_FREE(state);
9321 END_PROFILE(SMBtranss2);
9322 return;
9324 bad_param:
9326 DEBUG(0,("reply_transs2: invalid trans parameters\n"));
9327 DLIST_REMOVE(conn->pending_trans, state);
9328 SAFE_FREE(state->data);
9329 SAFE_FREE(state->param);
9330 TALLOC_FREE(state);
9331 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
9332 END_PROFILE(SMBtranss2);
9333 return;