torture: add new tests for dfsblobs
[Samba/gebeck_regimport.git] / source3 / smbd / trans2.c
blobcd4f605c39e7bd5f321abcced78fc57d09073ca3
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 "version.h"
28 #include "smbd/globals.h"
29 #include "../libcli/auth/libcli_auth.h"
31 #define DIR_ENTRY_SAFETY_MARGIN 4096
33 static char *store_file_unix_basic(connection_struct *conn,
34 char *pdata,
35 files_struct *fsp,
36 const SMB_STRUCT_STAT *psbuf);
38 static char *store_file_unix_basic_info2(connection_struct *conn,
39 char *pdata,
40 files_struct *fsp,
41 const SMB_STRUCT_STAT *psbuf);
43 /********************************************************************
44 Roundup a value to the nearest allocation roundup size boundary.
45 Only do this for Windows clients.
46 ********************************************************************/
48 uint64_t smb_roundup(connection_struct *conn, uint64_t val)
50 uint64_t rval = lp_allocation_roundup_size(SNUM(conn));
52 /* Only roundup for Windows clients. */
53 enum remote_arch_types ra_type = get_remote_arch();
54 if (rval && (ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
55 val = SMB_ROUNDUP(val,rval);
57 return val;
60 /****************************************************************************
61 Utility functions for dealing with extended attributes.
62 ****************************************************************************/
64 /****************************************************************************
65 Refuse to allow clients to overwrite our private xattrs.
66 ****************************************************************************/
68 static bool samba_private_attr_name(const char *unix_ea_name)
70 static const char * const prohibited_ea_names[] = {
71 SAMBA_POSIX_INHERITANCE_EA_NAME,
72 SAMBA_XATTR_DOS_ATTRIB,
73 SAMBA_XATTR_MARKER,
74 XATTR_NTACL_NAME,
75 NULL
78 int i;
80 for (i = 0; prohibited_ea_names[i]; i++) {
81 if (strequal( prohibited_ea_names[i], unix_ea_name))
82 return true;
84 if (StrnCaseCmp(unix_ea_name, SAMBA_XATTR_DOSSTREAM_PREFIX,
85 strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) == 0) {
86 return true;
88 return false;
91 /****************************************************************************
92 Get one EA value. Fill in a struct ea_struct.
93 ****************************************************************************/
95 NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn,
96 files_struct *fsp, const char *fname,
97 const char *ea_name, struct ea_struct *pea)
99 /* Get the value of this xattr. Max size is 64k. */
100 size_t attr_size = 256;
101 char *val = NULL;
102 ssize_t sizeret;
104 again:
106 val = TALLOC_REALLOC_ARRAY(mem_ctx, val, char, attr_size);
107 if (!val) {
108 return NT_STATUS_NO_MEMORY;
111 if (fsp && fsp->fh->fd != -1) {
112 sizeret = SMB_VFS_FGETXATTR(fsp, ea_name, val, attr_size);
113 } else {
114 sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size);
117 if (sizeret == -1 && errno == ERANGE && attr_size != 65536) {
118 attr_size = 65536;
119 goto again;
122 if (sizeret == -1) {
123 return map_nt_error_from_unix(errno);
126 DEBUG(10,("get_ea_value: EA %s is of length %u\n", ea_name, (unsigned int)sizeret));
127 dump_data(10, (uint8 *)val, sizeret);
129 pea->flags = 0;
130 if (strnequal(ea_name, "user.", 5)) {
131 pea->name = talloc_strdup(mem_ctx, &ea_name[5]);
132 } else {
133 pea->name = talloc_strdup(mem_ctx, ea_name);
135 if (pea->name == NULL) {
136 TALLOC_FREE(val);
137 return NT_STATUS_NO_MEMORY;
139 pea->value.data = (unsigned char *)val;
140 pea->value.length = (size_t)sizeret;
141 return NT_STATUS_OK;
144 NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
145 files_struct *fsp, const char *fname,
146 char ***pnames, size_t *pnum_names)
148 /* Get a list of all xattrs. Max namesize is 64k. */
149 size_t ea_namelist_size = 1024;
150 char *ea_namelist = NULL;
152 char *p;
153 char **names, **tmp;
154 size_t num_names;
155 ssize_t sizeret = -1;
157 if (!lp_ea_support(SNUM(conn))) {
158 if (pnames) {
159 *pnames = NULL;
161 *pnum_names = 0;
162 return NT_STATUS_OK;
166 * TALLOC the result early to get the talloc hierarchy right.
169 names = TALLOC_ARRAY(mem_ctx, char *, 1);
170 if (names == NULL) {
171 DEBUG(0, ("talloc failed\n"));
172 return NT_STATUS_NO_MEMORY;
175 while (ea_namelist_size <= 65536) {
177 ea_namelist = TALLOC_REALLOC_ARRAY(
178 names, ea_namelist, char, ea_namelist_size);
179 if (ea_namelist == NULL) {
180 DEBUG(0, ("talloc failed\n"));
181 TALLOC_FREE(names);
182 return NT_STATUS_NO_MEMORY;
185 if (fsp && fsp->fh->fd != -1) {
186 sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
187 ea_namelist_size);
188 } else {
189 sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist,
190 ea_namelist_size);
193 if ((sizeret == -1) && (errno == ERANGE)) {
194 ea_namelist_size *= 2;
196 else {
197 break;
201 if (sizeret == -1) {
202 TALLOC_FREE(names);
203 return map_nt_error_from_unix(errno);
206 DEBUG(10, ("get_ea_list_from_file: ea_namelist size = %u\n",
207 (unsigned int)sizeret));
209 if (sizeret == 0) {
210 TALLOC_FREE(names);
211 if (pnames) {
212 *pnames = NULL;
214 *pnum_names = 0;
215 return NT_STATUS_OK;
219 * Ensure the result is 0-terminated
222 if (ea_namelist[sizeret-1] != '\0') {
223 TALLOC_FREE(names);
224 return NT_STATUS_INTERNAL_ERROR;
228 * count the names
230 num_names = 0;
232 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
233 num_names += 1;
236 tmp = TALLOC_REALLOC_ARRAY(mem_ctx, names, char *, num_names);
237 if (tmp == NULL) {
238 DEBUG(0, ("talloc failed\n"));
239 TALLOC_FREE(names);
240 return NT_STATUS_NO_MEMORY;
243 names = tmp;
244 num_names = 0;
246 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
247 names[num_names++] = p;
250 if (pnames) {
251 *pnames = names;
252 } else {
253 TALLOC_FREE(names);
255 *pnum_names = num_names;
256 return NT_STATUS_OK;
259 /****************************************************************************
260 Return a linked list of the total EA's. Plus the total size
261 ****************************************************************************/
263 static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
264 const char *fname, size_t *pea_total_len)
266 /* Get a list of all xattrs. Max namesize is 64k. */
267 size_t i, num_names;
268 char **names;
269 struct ea_list *ea_list_head = NULL;
270 NTSTATUS status;
272 *pea_total_len = 0;
274 if (!lp_ea_support(SNUM(conn))) {
275 return NULL;
278 status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
279 &names, &num_names);
281 if (!NT_STATUS_IS_OK(status) || (num_names == 0)) {
282 return NULL;
285 for (i=0; i<num_names; i++) {
286 struct ea_list *listp;
287 fstring dos_ea_name;
289 if (strnequal(names[i], "system.", 7)
290 || samba_private_attr_name(names[i]))
291 continue;
293 listp = TALLOC_P(mem_ctx, struct ea_list);
294 if (listp == NULL) {
295 return NULL;
298 if (!NT_STATUS_IS_OK(get_ea_value(mem_ctx, conn, fsp,
299 fname, names[i],
300 &listp->ea))) {
301 return NULL;
304 push_ascii_fstring(dos_ea_name, listp->ea.name);
306 *pea_total_len +=
307 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
309 DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len "
310 "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
311 (unsigned int)listp->ea.value.length));
313 DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
317 /* Add on 4 for total length. */
318 if (*pea_total_len) {
319 *pea_total_len += 4;
322 DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
323 (unsigned int)*pea_total_len));
325 return ea_list_head;
328 /****************************************************************************
329 Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer
330 that was filled.
331 ****************************************************************************/
333 static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
334 connection_struct *conn, struct ea_list *ea_list)
336 unsigned int ret_data_size = 4;
337 char *p = pdata;
339 SMB_ASSERT(total_data_size >= 4);
341 if (!lp_ea_support(SNUM(conn))) {
342 SIVAL(pdata,4,0);
343 return 4;
346 for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
347 size_t dos_namelen;
348 fstring dos_ea_name;
349 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
350 dos_namelen = strlen(dos_ea_name);
351 if (dos_namelen > 255 || dos_namelen == 0) {
352 break;
354 if (ea_list->ea.value.length > 65535) {
355 break;
357 if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
358 break;
361 /* We know we have room. */
362 SCVAL(p,0,ea_list->ea.flags);
363 SCVAL(p,1,dos_namelen);
364 SSVAL(p,2,ea_list->ea.value.length);
365 fstrcpy(p+4, dos_ea_name);
366 memcpy( p + 4 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
368 total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
369 p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
372 ret_data_size = PTR_DIFF(p, pdata);
373 DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
374 SIVAL(pdata,0,ret_data_size);
375 return ret_data_size;
378 static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
379 char *pdata,
380 unsigned int total_data_size,
381 unsigned int *ret_data_size,
382 connection_struct *conn,
383 struct ea_list *ea_list)
385 uint8_t *p = (uint8_t *)pdata;
386 uint8_t *last_start = NULL;
388 *ret_data_size = 0;
390 if (!lp_ea_support(SNUM(conn))) {
391 return NT_STATUS_NO_EAS_ON_FILE;
394 for (; ea_list; ea_list = ea_list->next) {
395 size_t dos_namelen;
396 fstring dos_ea_name;
397 size_t this_size;
399 if (last_start) {
400 SIVAL(last_start, 0, PTR_DIFF(p, last_start));
402 last_start = p;
404 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
405 dos_namelen = strlen(dos_ea_name);
406 if (dos_namelen > 255 || dos_namelen == 0) {
407 return NT_STATUS_INTERNAL_ERROR;
409 if (ea_list->ea.value.length > 65535) {
410 return NT_STATUS_INTERNAL_ERROR;
413 this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length;
415 if (ea_list->next) {
416 size_t pad = 4 - (this_size % 4);
417 this_size += pad;
420 if (this_size > total_data_size) {
421 return NT_STATUS_INFO_LENGTH_MISMATCH;
424 /* We know we have room. */
425 SIVAL(p, 0x00, 0); /* next offset */
426 SCVAL(p, 0x04, ea_list->ea.flags);
427 SCVAL(p, 0x05, dos_namelen);
428 SSVAL(p, 0x06, ea_list->ea.value.length);
429 fstrcpy((char *)(p+0x08), dos_ea_name);
430 memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
432 total_data_size -= this_size;
433 p += this_size;
436 *ret_data_size = PTR_DIFF(p, pdata);
437 DEBUG(10,("fill_ea_chained_buffer: data_size = %u\n", *ret_data_size));
438 return NT_STATUS_OK;
441 static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname)
443 size_t total_ea_len = 0;
444 TALLOC_CTX *mem_ctx = NULL;
446 if (!lp_ea_support(SNUM(conn))) {
447 return 0;
449 mem_ctx = talloc_tos();
450 (void)get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
451 return total_ea_len;
454 /****************************************************************************
455 Ensure the EA name is case insensitive by matching any existing EA name.
456 ****************************************************************************/
458 static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, const char *fname, fstring unix_ea_name)
460 size_t total_ea_len;
461 TALLOC_CTX *mem_ctx = talloc_tos();
462 struct ea_list *ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
464 for (; ea_list; ea_list = ea_list->next) {
465 if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
466 DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
467 &unix_ea_name[5], ea_list->ea.name));
468 safe_strcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-6);
469 break;
474 /****************************************************************************
475 Set or delete an extended attribute.
476 ****************************************************************************/
478 NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
479 const struct smb_filename *smb_fname, struct ea_list *ea_list)
481 char *fname = NULL;
483 if (!lp_ea_support(SNUM(conn))) {
484 return NT_STATUS_EAS_NOT_SUPPORTED;
487 /* For now setting EAs on streams isn't supported. */
488 fname = smb_fname->base_name;
490 for (;ea_list; ea_list = ea_list->next) {
491 int ret;
492 fstring unix_ea_name;
494 fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
495 fstrcat(unix_ea_name, ea_list->ea.name);
497 canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
499 DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
501 if (samba_private_attr_name(unix_ea_name)) {
502 DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
503 return NT_STATUS_ACCESS_DENIED;
506 if (ea_list->ea.value.length == 0) {
507 /* Remove the attribute. */
508 if (fsp && (fsp->fh->fd != -1)) {
509 DEBUG(10,("set_ea: deleting ea name %s on "
510 "file %s by file descriptor.\n",
511 unix_ea_name, fsp_str_dbg(fsp)));
512 ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name);
513 } else {
514 DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",
515 unix_ea_name, fname));
516 ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);
518 #ifdef ENOATTR
519 /* Removing a non existent attribute always succeeds. */
520 if (ret == -1 && errno == ENOATTR) {
521 DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",
522 unix_ea_name));
523 ret = 0;
525 #endif
526 } else {
527 if (fsp && (fsp->fh->fd != -1)) {
528 DEBUG(10,("set_ea: setting ea name %s on file "
529 "%s by file descriptor.\n",
530 unix_ea_name, fsp_str_dbg(fsp)));
531 ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name,
532 ea_list->ea.value.data, ea_list->ea.value.length, 0);
533 } else {
534 DEBUG(10,("set_ea: setting ea name %s on file %s.\n",
535 unix_ea_name, fname));
536 ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name,
537 ea_list->ea.value.data, ea_list->ea.value.length, 0);
541 if (ret == -1) {
542 #ifdef ENOTSUP
543 if (errno == ENOTSUP) {
544 return NT_STATUS_EAS_NOT_SUPPORTED;
546 #endif
547 return map_nt_error_from_unix(errno);
551 return NT_STATUS_OK;
553 /****************************************************************************
554 Read a list of EA names from an incoming data buffer. Create an ea_list with them.
555 ****************************************************************************/
557 static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
559 struct ea_list *ea_list_head = NULL;
560 size_t converted_size, offset = 0;
562 while (offset + 2 < data_size) {
563 struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
564 unsigned int namelen = CVAL(pdata,offset);
566 offset++; /* Go past the namelen byte. */
568 /* integer wrap paranioa. */
569 if ((offset + namelen < offset) || (offset + namelen < namelen) ||
570 (offset > data_size) || (namelen > data_size) ||
571 (offset + namelen >= data_size)) {
572 break;
574 /* Ensure the name is null terminated. */
575 if (pdata[offset + namelen] != '\0') {
576 return NULL;
578 if (!pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset],
579 &converted_size)) {
580 DEBUG(0,("read_ea_name_list: pull_ascii_talloc "
581 "failed: %s", strerror(errno)));
583 if (!eal->ea.name) {
584 return NULL;
587 offset += (namelen + 1); /* Go past the name + terminating zero. */
588 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
589 DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
592 return ea_list_head;
595 /****************************************************************************
596 Read one EA list entry from the buffer.
597 ****************************************************************************/
599 struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used)
601 struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
602 uint16 val_len;
603 unsigned int namelen;
604 size_t converted_size;
606 if (!eal) {
607 return NULL;
610 if (data_size < 6) {
611 return NULL;
614 eal->ea.flags = CVAL(pdata,0);
615 namelen = CVAL(pdata,1);
616 val_len = SVAL(pdata,2);
618 if (4 + namelen + 1 + val_len > data_size) {
619 return NULL;
622 /* Ensure the name is null terminated. */
623 if (pdata[namelen + 4] != '\0') {
624 return NULL;
626 if (!pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4, &converted_size)) {
627 DEBUG(0,("read_ea_list_entry: pull_ascii_talloc failed: %s",
628 strerror(errno)));
630 if (!eal->ea.name) {
631 return NULL;
634 eal->ea.value = data_blob_talloc(eal, NULL, (size_t)val_len + 1);
635 if (!eal->ea.value.data) {
636 return NULL;
639 memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len);
641 /* Ensure we're null terminated just in case we print the value. */
642 eal->ea.value.data[val_len] = '\0';
643 /* But don't count the null. */
644 eal->ea.value.length--;
646 if (pbytes_used) {
647 *pbytes_used = 4 + namelen + 1 + val_len;
650 DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name));
651 dump_data(10, eal->ea.value.data, eal->ea.value.length);
653 return eal;
656 /****************************************************************************
657 Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
658 ****************************************************************************/
660 static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
662 struct ea_list *ea_list_head = NULL;
663 size_t offset = 0;
664 size_t bytes_used = 0;
666 while (offset < data_size) {
667 struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);
669 if (!eal) {
670 return NULL;
673 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
674 offset += bytes_used;
677 return ea_list_head;
680 /****************************************************************************
681 Count the total EA size needed.
682 ****************************************************************************/
684 static size_t ea_list_size(struct ea_list *ealist)
686 fstring dos_ea_name;
687 struct ea_list *listp;
688 size_t ret = 0;
690 for (listp = ealist; listp; listp = listp->next) {
691 push_ascii_fstring(dos_ea_name, listp->ea.name);
692 ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
694 /* Add on 4 for total length. */
695 if (ret) {
696 ret += 4;
699 return ret;
702 /****************************************************************************
703 Return a union of EA's from a file list and a list of names.
704 The TALLOC context for the two lists *MUST* be identical as we steal
705 memory from one list to add to another. JRA.
706 ****************************************************************************/
708 static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *file_list, size_t *total_ea_len)
710 struct ea_list *nlistp, *flistp;
712 for (nlistp = name_list; nlistp; nlistp = nlistp->next) {
713 for (flistp = file_list; flistp; flistp = flistp->next) {
714 if (strequal(nlistp->ea.name, flistp->ea.name)) {
715 break;
719 if (flistp) {
720 /* Copy the data from this entry. */
721 nlistp->ea.flags = flistp->ea.flags;
722 nlistp->ea.value = flistp->ea.value;
723 } else {
724 /* Null entry. */
725 nlistp->ea.flags = 0;
726 ZERO_STRUCT(nlistp->ea.value);
730 *total_ea_len = ea_list_size(name_list);
731 return name_list;
734 /****************************************************************************
735 Send the required number of replies back.
736 We assume all fields other than the data fields are
737 set correctly for the type of call.
738 HACK ! Always assumes smb_setup field is zero.
739 ****************************************************************************/
741 void send_trans2_replies(connection_struct *conn,
742 struct smb_request *req,
743 const char *params,
744 int paramsize,
745 const char *pdata,
746 int datasize,
747 int max_data_bytes)
749 /* As we are using a protocol > LANMAN1 then the max_send
750 variable must have been set in the sessetupX call.
751 This takes precedence over the max_xmit field in the
752 global struct. These different max_xmit variables should
753 be merged as this is now too confusing */
755 int data_to_send = datasize;
756 int params_to_send = paramsize;
757 int useable_space;
758 const char *pp = params;
759 const char *pd = pdata;
760 int params_sent_thistime, data_sent_thistime, total_sent_thistime;
761 int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
762 int data_alignment_offset = 0;
763 bool overflow = False;
764 struct smbd_server_connection *sconn = smbd_server_conn;
765 int max_send = sconn->smb1.sessions.max_send;
767 /* Modify the data_to_send and datasize and set the error if
768 we're trying to send more than max_data_bytes. We still send
769 the part of the packet(s) that fit. Strange, but needed
770 for OS/2. */
772 if (max_data_bytes > 0 && datasize > max_data_bytes) {
773 DEBUG(5,("send_trans2_replies: max_data_bytes %d exceeded by data %d\n",
774 max_data_bytes, datasize ));
775 datasize = data_to_send = max_data_bytes;
776 overflow = True;
779 /* If there genuinely are no parameters or data to send just send the empty packet */
781 if(params_to_send == 0 && data_to_send == 0) {
782 reply_outbuf(req, 10, 0);
783 show_msg((char *)req->outbuf);
784 if (!srv_send_smb(smbd_server_fd(),
785 (char *)req->outbuf,
786 true, req->seqnum+1,
787 IS_CONN_ENCRYPTED(conn),
788 &req->pcd)) {
789 exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
791 TALLOC_FREE(req->outbuf);
792 return;
795 /* When sending params and data ensure that both are nicely aligned */
796 /* Only do this alignment when there is also data to send - else
797 can cause NT redirector problems. */
799 if (((params_to_send % 4) != 0) && (data_to_send != 0))
800 data_alignment_offset = 4 - (params_to_send % 4);
802 /* Space is bufsize minus Netbios over TCP header minus SMB header */
803 /* The alignment_offset is to align the param bytes on an even byte
804 boundary. NT 4.0 Beta needs this to work correctly. */
806 useable_space = max_send - (smb_size
807 + 2 * 10 /* wct */
808 + alignment_offset
809 + data_alignment_offset);
811 if (useable_space < 0) {
812 DEBUG(0, ("send_trans2_replies failed sanity useable_space "
813 "= %d!!!", useable_space));
814 exit_server_cleanly("send_trans2_replies: Not enough space");
817 while (params_to_send || data_to_send) {
818 /* Calculate whether we will totally or partially fill this packet */
820 total_sent_thistime = params_to_send + data_to_send;
822 /* We can never send more than useable_space */
824 * Note that 'useable_space' does not include the alignment offsets,
825 * but we must include the alignment offsets in the calculation of
826 * the length of the data we send over the wire, as the alignment offsets
827 * are sent here. Fix from Marc_Jacobsen@hp.com.
830 total_sent_thistime = MIN(total_sent_thistime, useable_space);
832 reply_outbuf(req, 10, total_sent_thistime + alignment_offset
833 + data_alignment_offset);
836 * We might have SMBtrans2s in req which was transferred to
837 * the outbuf, fix that.
839 SCVAL(req->outbuf, smb_com, SMBtrans2);
841 /* Set total params and data to be sent */
842 SSVAL(req->outbuf,smb_tprcnt,paramsize);
843 SSVAL(req->outbuf,smb_tdrcnt,datasize);
845 /* Calculate how many parameters and data we can fit into
846 * this packet. Parameters get precedence
849 params_sent_thistime = MIN(params_to_send,useable_space);
850 data_sent_thistime = useable_space - params_sent_thistime;
851 data_sent_thistime = MIN(data_sent_thistime,data_to_send);
853 SSVAL(req->outbuf,smb_prcnt, params_sent_thistime);
855 /* smb_proff is the offset from the start of the SMB header to the
856 parameter bytes, however the first 4 bytes of outbuf are
857 the Netbios over TCP header. Thus use smb_base() to subtract
858 them from the calculation */
860 SSVAL(req->outbuf,smb_proff,
861 ((smb_buf(req->outbuf)+alignment_offset)
862 - smb_base(req->outbuf)));
864 if(params_sent_thistime == 0)
865 SSVAL(req->outbuf,smb_prdisp,0);
866 else
867 /* Absolute displacement of param bytes sent in this packet */
868 SSVAL(req->outbuf,smb_prdisp,pp - params);
870 SSVAL(req->outbuf,smb_drcnt, data_sent_thistime);
871 if(data_sent_thistime == 0) {
872 SSVAL(req->outbuf,smb_droff,0);
873 SSVAL(req->outbuf,smb_drdisp, 0);
874 } else {
875 /* The offset of the data bytes is the offset of the
876 parameter bytes plus the number of parameters being sent this time */
877 SSVAL(req->outbuf, smb_droff,
878 ((smb_buf(req->outbuf)+alignment_offset)
879 - smb_base(req->outbuf))
880 + params_sent_thistime + data_alignment_offset);
881 SSVAL(req->outbuf,smb_drdisp, pd - pdata);
884 /* Initialize the padding for alignment */
886 if (alignment_offset != 0) {
887 memset(smb_buf(req->outbuf), 0, alignment_offset);
890 /* Copy the param bytes into the packet */
892 if(params_sent_thistime) {
893 memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
894 params_sent_thistime);
897 /* Copy in the data bytes */
898 if(data_sent_thistime) {
899 if (data_alignment_offset != 0) {
900 memset((smb_buf(req->outbuf)+alignment_offset+
901 params_sent_thistime), 0,
902 data_alignment_offset);
904 memcpy(smb_buf(req->outbuf)+alignment_offset
905 +params_sent_thistime+data_alignment_offset,
906 pd,data_sent_thistime);
909 DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
910 params_sent_thistime, data_sent_thistime, useable_space));
911 DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
912 params_to_send, data_to_send, paramsize, datasize));
914 if (overflow) {
915 error_packet_set((char *)req->outbuf,
916 ERRDOS,ERRbufferoverflow,
917 STATUS_BUFFER_OVERFLOW,
918 __LINE__,__FILE__);
921 /* Send the packet */
922 show_msg((char *)req->outbuf);
923 if (!srv_send_smb(smbd_server_fd(),
924 (char *)req->outbuf,
925 true, req->seqnum+1,
926 IS_CONN_ENCRYPTED(conn),
927 &req->pcd))
928 exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
930 TALLOC_FREE(req->outbuf);
932 pp += params_sent_thistime;
933 pd += data_sent_thistime;
935 params_to_send -= params_sent_thistime;
936 data_to_send -= data_sent_thistime;
938 /* Sanity check */
939 if(params_to_send < 0 || data_to_send < 0) {
940 DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
941 params_to_send, data_to_send));
942 return;
946 return;
949 /****************************************************************************
950 Reply to a TRANSACT2_OPEN.
951 ****************************************************************************/
953 static void call_trans2open(connection_struct *conn,
954 struct smb_request *req,
955 char **pparams, int total_params,
956 char **ppdata, int total_data,
957 unsigned int max_data_bytes)
959 struct smb_filename *smb_fname = NULL;
960 char *params = *pparams;
961 char *pdata = *ppdata;
962 int deny_mode;
963 int32 open_attr;
964 bool oplock_request;
965 #if 0
966 bool return_additional_info;
967 int16 open_sattr;
968 time_t open_time;
969 #endif
970 int open_ofun;
971 uint32 open_size;
972 char *pname;
973 char *fname = NULL;
974 SMB_OFF_T size=0;
975 int fattr=0,mtime=0;
976 SMB_INO_T inode = 0;
977 int smb_action = 0;
978 files_struct *fsp;
979 struct ea_list *ea_list = NULL;
980 uint16 flags = 0;
981 NTSTATUS status;
982 uint32 access_mask;
983 uint32 share_mode;
984 uint32 create_disposition;
985 uint32 create_options = 0;
986 TALLOC_CTX *ctx = talloc_tos();
989 * Ensure we have enough parameters to perform the operation.
992 if (total_params < 29) {
993 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
994 goto out;
997 flags = SVAL(params, 0);
998 deny_mode = SVAL(params, 2);
999 open_attr = SVAL(params,6);
1000 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
1001 if (oplock_request) {
1002 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
1005 #if 0
1006 return_additional_info = BITSETW(params,0);
1007 open_sattr = SVAL(params, 4);
1008 open_time = make_unix_date3(params+8);
1009 #endif
1010 open_ofun = SVAL(params,12);
1011 open_size = IVAL(params,14);
1012 pname = &params[28];
1014 if (IS_IPC(conn)) {
1015 reply_doserror(req, ERRSRV, ERRaccess);
1016 goto out;
1019 srvstr_get_path(ctx, params, req->flags2, &fname, pname,
1020 total_params - 28, STR_TERMINATE,
1021 &status);
1022 if (!NT_STATUS_IS_OK(status)) {
1023 reply_nterror(req, status);
1024 goto out;
1027 DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n",
1028 fname, (unsigned int)deny_mode, (unsigned int)open_attr,
1029 (unsigned int)open_ofun, open_size));
1031 status = filename_convert(ctx,
1032 conn,
1033 req->flags2 & FLAGS2_DFS_PATHNAMES,
1034 fname,
1036 NULL,
1037 &smb_fname);
1038 if (!NT_STATUS_IS_OK(status)) {
1039 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1040 reply_botherror(req,
1041 NT_STATUS_PATH_NOT_COVERED,
1042 ERRSRV, ERRbadpath);
1043 goto out;
1045 reply_nterror(req, status);
1046 goto out;
1049 if (open_ofun == 0) {
1050 reply_nterror(req, NT_STATUS_OBJECT_NAME_COLLISION);
1051 goto out;
1054 if (!map_open_params_to_ntcreate(smb_fname, deny_mode, open_ofun,
1055 &access_mask, &share_mode,
1056 &create_disposition,
1057 &create_options)) {
1058 reply_doserror(req, ERRDOS, ERRbadaccess);
1059 goto out;
1062 /* Any data in this call is an EA list. */
1063 if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
1064 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
1065 goto out;
1068 if (total_data != 4) {
1069 if (total_data < 10) {
1070 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1071 goto out;
1074 if (IVAL(pdata,0) > total_data) {
1075 DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n",
1076 IVAL(pdata,0), (unsigned int)total_data));
1077 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1078 goto out;
1081 ea_list = read_ea_list(talloc_tos(), pdata + 4,
1082 total_data - 4);
1083 if (!ea_list) {
1084 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1085 goto out;
1087 } else if (IVAL(pdata,0) != 4) {
1088 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1089 goto out;
1092 status = SMB_VFS_CREATE_FILE(
1093 conn, /* conn */
1094 req, /* req */
1095 0, /* root_dir_fid */
1096 smb_fname, /* fname */
1097 access_mask, /* access_mask */
1098 share_mode, /* share_access */
1099 create_disposition, /* create_disposition*/
1100 create_options, /* create_options */
1101 open_attr, /* file_attributes */
1102 oplock_request, /* oplock_request */
1103 open_size, /* allocation_size */
1104 NULL, /* sd */
1105 ea_list, /* ea_list */
1106 &fsp, /* result */
1107 &smb_action); /* psbuf */
1109 if (!NT_STATUS_IS_OK(status)) {
1110 if (open_was_deferred(req->mid)) {
1111 /* We have re-scheduled this call. */
1112 goto out;
1114 reply_openerror(req, status);
1115 goto out;
1118 size = get_file_size_stat(&smb_fname->st);
1119 fattr = dos_mode(conn, smb_fname);
1120 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1121 inode = smb_fname->st.st_ex_ino;
1122 if (fattr & aDIR) {
1123 close_file(req, fsp, ERROR_CLOSE);
1124 reply_doserror(req, ERRDOS,ERRnoaccess);
1125 goto out;
1128 /* Realloc the size of parameters and data we will return */
1129 *pparams = (char *)SMB_REALLOC(*pparams, 30);
1130 if(*pparams == NULL ) {
1131 reply_nterror(req, NT_STATUS_NO_MEMORY);
1132 goto out;
1134 params = *pparams;
1136 SSVAL(params,0,fsp->fnum);
1137 SSVAL(params,2,fattr);
1138 srv_put_dos_date2(params,4, mtime);
1139 SIVAL(params,8, (uint32)size);
1140 SSVAL(params,12,deny_mode);
1141 SSVAL(params,14,0); /* open_type - file or directory. */
1142 SSVAL(params,16,0); /* open_state - only valid for IPC device. */
1144 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1145 smb_action |= EXTENDED_OPLOCK_GRANTED;
1148 SSVAL(params,18,smb_action);
1151 * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
1153 SIVAL(params,20,inode);
1154 SSVAL(params,24,0); /* Padding. */
1155 if (flags & 8) {
1156 uint32 ea_size = estimate_ea_size(conn, fsp,
1157 fsp->fsp_name->base_name);
1158 SIVAL(params, 26, ea_size);
1159 } else {
1160 SIVAL(params, 26, 0);
1163 /* Send the required number of replies */
1164 send_trans2_replies(conn, req, params, 30, *ppdata, 0, max_data_bytes);
1165 out:
1166 TALLOC_FREE(smb_fname);
1169 /*********************************************************
1170 Routine to check if a given string matches exactly.
1171 as a special case a mask of "." does NOT match. That
1172 is required for correct wildcard semantics
1173 Case can be significant or not.
1174 **********************************************************/
1176 static bool exact_match(bool has_wild,
1177 bool case_sensitive,
1178 const char *str,
1179 const char *mask)
1181 if (mask[0] == '.' && mask[1] == 0) {
1182 return false;
1185 if (has_wild) {
1186 return false;
1189 if (case_sensitive) {
1190 return strcmp(str,mask)==0;
1191 } else {
1192 return StrCaseCmp(str,mask) == 0;
1196 /****************************************************************************
1197 Return the filetype for UNIX extensions.
1198 ****************************************************************************/
1200 static uint32 unix_filetype(mode_t mode)
1202 if(S_ISREG(mode))
1203 return UNIX_TYPE_FILE;
1204 else if(S_ISDIR(mode))
1205 return UNIX_TYPE_DIR;
1206 #ifdef S_ISLNK
1207 else if(S_ISLNK(mode))
1208 return UNIX_TYPE_SYMLINK;
1209 #endif
1210 #ifdef S_ISCHR
1211 else if(S_ISCHR(mode))
1212 return UNIX_TYPE_CHARDEV;
1213 #endif
1214 #ifdef S_ISBLK
1215 else if(S_ISBLK(mode))
1216 return UNIX_TYPE_BLKDEV;
1217 #endif
1218 #ifdef S_ISFIFO
1219 else if(S_ISFIFO(mode))
1220 return UNIX_TYPE_FIFO;
1221 #endif
1222 #ifdef S_ISSOCK
1223 else if(S_ISSOCK(mode))
1224 return UNIX_TYPE_SOCKET;
1225 #endif
1227 DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode));
1228 return UNIX_TYPE_UNKNOWN;
1231 /****************************************************************************
1232 Map wire perms onto standard UNIX permissions. Obey share restrictions.
1233 ****************************************************************************/
1235 enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_DIR};
1237 static NTSTATUS unix_perms_from_wire( connection_struct *conn,
1238 const SMB_STRUCT_STAT *psbuf,
1239 uint32 perms,
1240 enum perm_type ptype,
1241 mode_t *ret_perms)
1243 mode_t ret = 0;
1245 if (perms == SMB_MODE_NO_CHANGE) {
1246 if (!VALID_STAT(*psbuf)) {
1247 return NT_STATUS_INVALID_PARAMETER;
1248 } else {
1249 *ret_perms = psbuf->st_ex_mode;
1250 return NT_STATUS_OK;
1254 ret |= ((perms & UNIX_X_OTH ) ? S_IXOTH : 0);
1255 ret |= ((perms & UNIX_W_OTH ) ? S_IWOTH : 0);
1256 ret |= ((perms & UNIX_R_OTH ) ? S_IROTH : 0);
1257 ret |= ((perms & UNIX_X_GRP ) ? S_IXGRP : 0);
1258 ret |= ((perms & UNIX_W_GRP ) ? S_IWGRP : 0);
1259 ret |= ((perms & UNIX_R_GRP ) ? S_IRGRP : 0);
1260 ret |= ((perms & UNIX_X_USR ) ? S_IXUSR : 0);
1261 ret |= ((perms & UNIX_W_USR ) ? S_IWUSR : 0);
1262 ret |= ((perms & UNIX_R_USR ) ? S_IRUSR : 0);
1263 #ifdef S_ISVTX
1264 ret |= ((perms & UNIX_STICKY ) ? S_ISVTX : 0);
1265 #endif
1266 #ifdef S_ISGID
1267 ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0);
1268 #endif
1269 #ifdef S_ISUID
1270 ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0);
1271 #endif
1273 switch (ptype) {
1274 case PERM_NEW_FILE:
1275 /* Apply mode mask */
1276 ret &= lp_create_mask(SNUM(conn));
1277 /* Add in force bits */
1278 ret |= lp_force_create_mode(SNUM(conn));
1279 break;
1280 case PERM_NEW_DIR:
1281 ret &= lp_dir_mask(SNUM(conn));
1282 /* Add in force bits */
1283 ret |= lp_force_dir_mode(SNUM(conn));
1284 break;
1285 case PERM_EXISTING_FILE:
1286 /* Apply mode mask */
1287 ret &= lp_security_mask(SNUM(conn));
1288 /* Add in force bits */
1289 ret |= lp_force_security_mode(SNUM(conn));
1290 break;
1291 case PERM_EXISTING_DIR:
1292 /* Apply mode mask */
1293 ret &= lp_dir_security_mask(SNUM(conn));
1294 /* Add in force bits */
1295 ret |= lp_force_dir_security_mode(SNUM(conn));
1296 break;
1299 *ret_perms = ret;
1300 return NT_STATUS_OK;
1303 /****************************************************************************
1304 Needed to show the msdfs symlinks as directories. Modifies psbuf
1305 to be a directory if it's a msdfs link.
1306 ****************************************************************************/
1308 static bool check_msdfs_link(connection_struct *conn,
1309 const char *pathname,
1310 SMB_STRUCT_STAT *psbuf)
1312 int saved_errno = errno;
1313 if(lp_host_msdfs() &&
1314 lp_msdfs_root(SNUM(conn)) &&
1315 is_msdfs_link(conn, pathname, psbuf)) {
1317 DEBUG(5,("check_msdfs_link: Masquerading msdfs link %s "
1318 "as a directory\n",
1319 pathname));
1320 psbuf->st_ex_mode = (psbuf->st_ex_mode & 0xFFF) | S_IFDIR;
1321 errno = saved_errno;
1322 return true;
1324 errno = saved_errno;
1325 return false;
1329 /****************************************************************************
1330 Get a level dependent lanman2 dir entry.
1331 ****************************************************************************/
1333 struct smbd_dirptr_lanman2_state {
1334 connection_struct *conn;
1335 uint32_t info_level;
1336 bool check_mangled_names;
1337 bool has_wild;
1338 bool got_exact_match;
1341 static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx,
1342 void *private_data,
1343 const char *dname,
1344 const char *mask,
1345 char **_fname)
1347 struct smbd_dirptr_lanman2_state *state =
1348 (struct smbd_dirptr_lanman2_state *)private_data;
1349 bool ok;
1350 char mangled_name[13]; /* mangled 8.3 name. */
1351 bool got_match;
1352 const char *fname;
1354 /* Mangle fname if it's an illegal name. */
1355 if (mangle_must_mangle(dname, state->conn->params)) {
1356 ok = name_to_8_3(dname, mangled_name,
1357 true, state->conn->params);
1358 if (!ok) {
1359 return false;
1361 fname = mangled_name;
1362 } else {
1363 fname = dname;
1366 got_match = exact_match(state->has_wild,
1367 state->conn->case_sensitive,
1368 fname, mask);
1369 state->got_exact_match = got_match;
1370 if (!got_match) {
1371 got_match = mask_match(fname, mask,
1372 state->conn->case_sensitive);
1375 if(!got_match && state->check_mangled_names &&
1376 !mangle_is_8_3(fname, false, state->conn->params)) {
1378 * It turns out that NT matches wildcards against
1379 * both long *and* short names. This may explain some
1380 * of the wildcard wierdness from old DOS clients
1381 * that some people have been seeing.... JRA.
1383 /* Force the mangling into 8.3. */
1384 ok = name_to_8_3(fname, mangled_name,
1385 false, state->conn->params);
1386 if (!ok) {
1387 return false;
1390 got_match = exact_match(state->has_wild,
1391 state->conn->case_sensitive,
1392 mangled_name, mask);
1393 state->got_exact_match = got_match;
1394 if (!got_match) {
1395 got_match = mask_match(mangled_name, mask,
1396 state->conn->case_sensitive);
1400 if (!got_match) {
1401 return false;
1404 *_fname = talloc_strdup(ctx, fname);
1405 if (*_fname == NULL) {
1406 return false;
1409 return true;
1412 static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
1413 void *private_data,
1414 struct smb_filename *smb_fname,
1415 uint32_t *_mode)
1417 struct smbd_dirptr_lanman2_state *state =
1418 (struct smbd_dirptr_lanman2_state *)private_data;
1419 bool ms_dfs_link = false;
1420 uint32_t mode = 0;
1422 if (INFO_LEVEL_IS_UNIX(state->info_level)) {
1423 if (SMB_VFS_LSTAT(state->conn, smb_fname) != 0) {
1424 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1425 "Couldn't lstat [%s] (%s)\n",
1426 smb_fname_str_dbg(smb_fname),
1427 strerror(errno)));
1428 return false;
1430 } else if (!VALID_STAT(smb_fname->st) &&
1431 SMB_VFS_STAT(state->conn, smb_fname) != 0) {
1432 /* Needed to show the msdfs symlinks as
1433 * directories */
1435 ms_dfs_link = check_msdfs_link(state->conn,
1436 smb_fname->base_name,
1437 &smb_fname->st);
1438 if (!ms_dfs_link) {
1439 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1440 "Couldn't stat [%s] (%s)\n",
1441 smb_fname_str_dbg(smb_fname),
1442 strerror(errno)));
1443 return false;
1447 if (ms_dfs_link) {
1448 mode = dos_mode_msdfs(state->conn, smb_fname);
1449 } else {
1450 mode = dos_mode(state->conn, smb_fname);
1453 *_mode = mode;
1454 return true;
1457 static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
1458 connection_struct *conn,
1459 uint16_t flags2,
1460 uint32_t info_level,
1461 struct ea_list *name_list,
1462 bool check_mangled_names,
1463 bool requires_resume_key,
1464 uint32_t mode,
1465 const char *fname,
1466 const struct smb_filename *smb_fname,
1467 uint64_t space_remaining,
1468 uint8_t align,
1469 bool do_pad,
1470 char *base_data,
1471 char **ppdata,
1472 char *end_data,
1473 bool *out_of_space,
1474 uint64_t *last_entry_off)
1476 char *p, *q, *pdata = *ppdata;
1477 uint32_t reskey=0;
1478 uint64_t file_size = 0;
1479 uint64_t allocation_size = 0;
1480 uint32_t len;
1481 struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts;
1482 time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
1483 time_t c_date = (time_t)0;
1484 char *nameptr;
1485 char *last_entry_ptr;
1486 bool was_8_3;
1487 uint32_t nt_extmode; /* Used for NT connections instead of mode */
1488 off_t off;
1489 off_t pad = 0;
1491 *out_of_space = false;
1493 ZERO_STRUCT(mdate_ts);
1494 ZERO_STRUCT(adate_ts);
1495 ZERO_STRUCT(create_date_ts);
1496 ZERO_STRUCT(cdate_ts);
1498 if (!(mode & aDIR)) {
1499 file_size = get_file_size_stat(&smb_fname->st);
1501 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
1503 mdate_ts = smb_fname->st.st_ex_mtime;
1504 adate_ts = smb_fname->st.st_ex_atime;
1505 create_date_ts = get_create_timespec(conn, NULL, smb_fname);
1506 cdate_ts = get_change_timespec(conn, NULL, smb_fname);
1508 if (lp_dos_filetime_resolution(SNUM(conn))) {
1509 dos_filetime_timespec(&create_date_ts);
1510 dos_filetime_timespec(&mdate_ts);
1511 dos_filetime_timespec(&adate_ts);
1512 dos_filetime_timespec(&cdate_ts);
1515 create_date = convert_timespec_to_time_t(create_date_ts);
1516 mdate = convert_timespec_to_time_t(mdate_ts);
1517 adate = convert_timespec_to_time_t(adate_ts);
1518 c_date = convert_timespec_to_time_t(cdate_ts);
1520 /* align the record */
1521 off = PTR_DIFF(pdata, base_data);
1522 pad = (off + (align-1)) & ~(align-1);
1523 pad -= off;
1524 off += pad;
1525 /* initialize padding to 0 */
1526 if (pad) {
1527 memset(pdata, 0, pad);
1529 space_remaining -= pad;
1531 pdata += pad;
1532 p = pdata;
1533 last_entry_ptr = p;
1535 pad = 0;
1536 off = 0;
1538 nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
1540 switch (info_level) {
1541 case SMB_FIND_INFO_STANDARD:
1542 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_INFO_STANDARD\n"));
1543 if(requires_resume_key) {
1544 SIVAL(p,0,reskey);
1545 p += 4;
1547 srv_put_dos_date2(p,0,create_date);
1548 srv_put_dos_date2(p,4,adate);
1549 srv_put_dos_date2(p,8,mdate);
1550 SIVAL(p,12,(uint32)file_size);
1551 SIVAL(p,16,(uint32)allocation_size);
1552 SSVAL(p,20,mode);
1553 p += 23;
1554 nameptr = p;
1555 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1556 p += ucs2_align(base_data, p, 0);
1558 len = srvstr_push(base_data, flags2, p,
1559 fname, PTR_DIFF(end_data, p),
1560 STR_TERMINATE);
1561 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1562 if (len > 2) {
1563 SCVAL(nameptr, -1, len - 2);
1564 } else {
1565 SCVAL(nameptr, -1, 0);
1567 } else {
1568 if (len > 1) {
1569 SCVAL(nameptr, -1, len - 1);
1570 } else {
1571 SCVAL(nameptr, -1, 0);
1574 p += len;
1575 break;
1577 case SMB_FIND_EA_SIZE:
1578 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_SIZE\n"));
1579 if (requires_resume_key) {
1580 SIVAL(p,0,reskey);
1581 p += 4;
1583 srv_put_dos_date2(p,0,create_date);
1584 srv_put_dos_date2(p,4,adate);
1585 srv_put_dos_date2(p,8,mdate);
1586 SIVAL(p,12,(uint32)file_size);
1587 SIVAL(p,16,(uint32)allocation_size);
1588 SSVAL(p,20,mode);
1590 unsigned int ea_size = estimate_ea_size(conn, NULL,
1591 smb_fname->base_name);
1592 SIVAL(p,22,ea_size); /* Extended attributes */
1594 p += 27;
1595 nameptr = p - 1;
1596 len = srvstr_push(base_data, flags2,
1597 p, fname, PTR_DIFF(end_data, p),
1598 STR_TERMINATE | STR_NOALIGN);
1599 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1600 if (len > 2) {
1601 len -= 2;
1602 } else {
1603 len = 0;
1605 } else {
1606 if (len > 1) {
1607 len -= 1;
1608 } else {
1609 len = 0;
1612 SCVAL(nameptr,0,len);
1613 p += len;
1614 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1615 break;
1617 case SMB_FIND_EA_LIST:
1619 struct ea_list *file_list = NULL;
1620 size_t ea_len = 0;
1622 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_LIST\n"));
1623 if (!name_list) {
1624 return false;
1626 if (requires_resume_key) {
1627 SIVAL(p,0,reskey);
1628 p += 4;
1630 srv_put_dos_date2(p,0,create_date);
1631 srv_put_dos_date2(p,4,adate);
1632 srv_put_dos_date2(p,8,mdate);
1633 SIVAL(p,12,(uint32)file_size);
1634 SIVAL(p,16,(uint32)allocation_size);
1635 SSVAL(p,20,mode);
1636 p += 22; /* p now points to the EA area. */
1638 file_list = get_ea_list_from_file(ctx, conn, NULL,
1639 smb_fname->base_name,
1640 &ea_len);
1641 name_list = ea_list_union(name_list, file_list, &ea_len);
1643 /* We need to determine if this entry will fit in the space available. */
1644 /* Max string size is 255 bytes. */
1645 if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
1646 *out_of_space = true;
1647 DEBUG(9,("smbd_marshall_dir_entry: out of space\n"));
1648 return False; /* Not finished - just out of space */
1651 /* Push the ea_data followed by the name. */
1652 p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
1653 nameptr = p;
1654 len = srvstr_push(base_data, flags2,
1655 p + 1, fname, PTR_DIFF(end_data, p+1),
1656 STR_TERMINATE | STR_NOALIGN);
1657 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1658 if (len > 2) {
1659 len -= 2;
1660 } else {
1661 len = 0;
1663 } else {
1664 if (len > 1) {
1665 len -= 1;
1666 } else {
1667 len = 0;
1670 SCVAL(nameptr,0,len);
1671 p += len + 1;
1672 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1673 break;
1676 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
1677 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
1678 was_8_3 = mangle_is_8_3(fname, True, conn->params);
1679 p += 4;
1680 SIVAL(p,0,reskey); p += 4;
1681 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1682 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1683 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1684 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1685 SOFF_T(p,0,file_size); p += 8;
1686 SOFF_T(p,0,allocation_size); p += 8;
1687 SIVAL(p,0,nt_extmode); p += 4;
1688 q = p; p += 4; /* q is placeholder for name length. */
1690 unsigned int ea_size = estimate_ea_size(conn, NULL,
1691 smb_fname->base_name);
1692 SIVAL(p,0,ea_size); /* Extended attributes */
1693 p += 4;
1695 /* Clear the short name buffer. This is
1696 * IMPORTANT as not doing so will trigger
1697 * a Win2k client bug. JRA.
1699 if (!was_8_3 && check_mangled_names) {
1700 char mangled_name[13]; /* mangled 8.3 name. */
1701 if (!name_to_8_3(fname,mangled_name,True,
1702 conn->params)) {
1703 /* Error - mangle failed ! */
1704 memset(mangled_name,'\0',12);
1706 mangled_name[12] = 0;
1707 len = srvstr_push(base_data, flags2,
1708 p+2, mangled_name, 24,
1709 STR_UPPER|STR_UNICODE);
1710 if (len < 24) {
1711 memset(p + 2 + len,'\0',24 - len);
1713 SSVAL(p, 0, len);
1714 } else {
1715 memset(p,'\0',26);
1717 p += 2 + 24;
1718 len = srvstr_push(base_data, flags2, p,
1719 fname, PTR_DIFF(end_data, p),
1720 STR_TERMINATE_ASCII);
1721 SIVAL(q,0,len);
1722 p += len;
1724 len = PTR_DIFF(p, pdata);
1725 pad = (len + (align-1)) & ~(align-1);
1727 * offset to the next entry, the caller
1728 * will overwrite it for the last entry
1729 * that's why we always include the padding
1731 SIVAL(pdata,0,pad);
1733 * set padding to zero
1735 if (do_pad) {
1736 memset(p, 0, pad - len);
1737 p = pdata + pad;
1738 } else {
1739 p = pdata + len;
1741 break;
1743 case SMB_FIND_FILE_DIRECTORY_INFO:
1744 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
1745 p += 4;
1746 SIVAL(p,0,reskey); p += 4;
1747 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1748 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1749 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1750 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1751 SOFF_T(p,0,file_size); p += 8;
1752 SOFF_T(p,0,allocation_size); p += 8;
1753 SIVAL(p,0,nt_extmode); p += 4;
1754 len = srvstr_push(base_data, flags2,
1755 p + 4, fname, PTR_DIFF(end_data, p+4),
1756 STR_TERMINATE_ASCII);
1757 SIVAL(p,0,len);
1758 p += 4 + len;
1760 len = PTR_DIFF(p, pdata);
1761 pad = (len + (align-1)) & ~(align-1);
1763 * offset to the next entry, the caller
1764 * will overwrite it for the last entry
1765 * that's why we always include the padding
1767 SIVAL(pdata,0,pad);
1769 * set padding to zero
1771 if (do_pad) {
1772 memset(p, 0, pad - len);
1773 p = pdata + pad;
1774 } else {
1775 p = pdata + len;
1777 break;
1779 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
1780 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
1781 p += 4;
1782 SIVAL(p,0,reskey); p += 4;
1783 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1784 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1785 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1786 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1787 SOFF_T(p,0,file_size); p += 8;
1788 SOFF_T(p,0,allocation_size); p += 8;
1789 SIVAL(p,0,nt_extmode); p += 4;
1790 q = p; p += 4; /* q is placeholder for name length. */
1792 unsigned int ea_size = estimate_ea_size(conn, NULL,
1793 smb_fname->base_name);
1794 SIVAL(p,0,ea_size); /* Extended attributes */
1795 p +=4;
1797 len = srvstr_push(base_data, flags2, p,
1798 fname, PTR_DIFF(end_data, p),
1799 STR_TERMINATE_ASCII);
1800 SIVAL(q, 0, len);
1801 p += len;
1803 len = PTR_DIFF(p, pdata);
1804 pad = (len + (align-1)) & ~(align-1);
1806 * offset to the next entry, the caller
1807 * will overwrite it for the last entry
1808 * that's why we always include the padding
1810 SIVAL(pdata,0,pad);
1812 * set padding to zero
1814 if (do_pad) {
1815 memset(p, 0, pad - len);
1816 p = pdata + pad;
1817 } else {
1818 p = pdata + len;
1820 break;
1822 case SMB_FIND_FILE_NAMES_INFO:
1823 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
1824 p += 4;
1825 SIVAL(p,0,reskey); p += 4;
1826 p += 4;
1827 /* this must *not* be null terminated or w2k gets in a loop trying to set an
1828 acl on a dir (tridge) */
1829 len = srvstr_push(base_data, flags2, p,
1830 fname, PTR_DIFF(end_data, p),
1831 STR_TERMINATE_ASCII);
1832 SIVAL(p, -4, len);
1833 p += len;
1835 len = PTR_DIFF(p, pdata);
1836 pad = (len + (align-1)) & ~(align-1);
1838 * offset to the next entry, the caller
1839 * will overwrite it for the last entry
1840 * that's why we always include the padding
1842 SIVAL(pdata,0,pad);
1844 * set padding to zero
1846 if (do_pad) {
1847 memset(p, 0, pad - len);
1848 p = pdata + pad;
1849 } else {
1850 p = pdata + len;
1852 break;
1854 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
1855 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
1856 p += 4;
1857 SIVAL(p,0,reskey); p += 4;
1858 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1859 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1860 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1861 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1862 SOFF_T(p,0,file_size); p += 8;
1863 SOFF_T(p,0,allocation_size); p += 8;
1864 SIVAL(p,0,nt_extmode); p += 4;
1865 q = p; p += 4; /* q is placeholder for name length. */
1867 unsigned int ea_size = estimate_ea_size(conn, NULL,
1868 smb_fname->base_name);
1869 SIVAL(p,0,ea_size); /* Extended attributes */
1870 p +=4;
1872 SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
1873 SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
1874 SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
1875 len = srvstr_push(base_data, flags2, p,
1876 fname, PTR_DIFF(end_data, p),
1877 STR_TERMINATE_ASCII);
1878 SIVAL(q, 0, len);
1879 p += len;
1881 len = PTR_DIFF(p, pdata);
1882 pad = (len + (align-1)) & ~(align-1);
1884 * offset to the next entry, the caller
1885 * will overwrite it for the last entry
1886 * that's why we always include the padding
1888 SIVAL(pdata,0,pad);
1890 * set padding to zero
1892 if (do_pad) {
1893 memset(p, 0, pad - len);
1894 p = pdata + pad;
1895 } else {
1896 p = pdata + len;
1898 break;
1900 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
1901 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
1902 was_8_3 = mangle_is_8_3(fname, True, conn->params);
1903 p += 4;
1904 SIVAL(p,0,reskey); p += 4;
1905 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1906 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1907 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1908 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1909 SOFF_T(p,0,file_size); p += 8;
1910 SOFF_T(p,0,allocation_size); p += 8;
1911 SIVAL(p,0,nt_extmode); p += 4;
1912 q = p; p += 4; /* q is placeholder for name length */
1914 unsigned int ea_size = estimate_ea_size(conn, NULL,
1915 smb_fname->base_name);
1916 SIVAL(p,0,ea_size); /* Extended attributes */
1917 p +=4;
1919 /* Clear the short name buffer. This is
1920 * IMPORTANT as not doing so will trigger
1921 * a Win2k client bug. JRA.
1923 if (!was_8_3 && check_mangled_names) {
1924 char mangled_name[13]; /* mangled 8.3 name. */
1925 if (!name_to_8_3(fname,mangled_name,True,
1926 conn->params)) {
1927 /* Error - mangle failed ! */
1928 memset(mangled_name,'\0',12);
1930 mangled_name[12] = 0;
1931 len = srvstr_push(base_data, flags2,
1932 p+2, mangled_name, 24,
1933 STR_UPPER|STR_UNICODE);
1934 SSVAL(p, 0, len);
1935 if (len < 24) {
1936 memset(p + 2 + len,'\0',24 - len);
1938 SSVAL(p, 0, len);
1939 } else {
1940 memset(p,'\0',26);
1942 p += 26;
1943 SSVAL(p,0,0); p += 2; /* Reserved ? */
1944 SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
1945 SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
1946 len = srvstr_push(base_data, flags2, p,
1947 fname, PTR_DIFF(end_data, p),
1948 STR_TERMINATE_ASCII);
1949 SIVAL(q,0,len);
1950 p += len;
1952 len = PTR_DIFF(p, pdata);
1953 pad = (len + (align-1)) & ~(align-1);
1955 * offset to the next entry, the caller
1956 * will overwrite it for the last entry
1957 * that's why we always include the padding
1959 SIVAL(pdata,0,pad);
1961 * set padding to zero
1963 if (do_pad) {
1964 memset(p, 0, pad - len);
1965 p = pdata + pad;
1966 } else {
1967 p = pdata + len;
1969 break;
1971 /* CIFS UNIX Extension. */
1973 case SMB_FIND_FILE_UNIX:
1974 case SMB_FIND_FILE_UNIX_INFO2:
1975 p+= 4;
1976 SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
1978 /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
1980 if (info_level == SMB_FIND_FILE_UNIX) {
1981 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX\n"));
1982 p = store_file_unix_basic(conn, p,
1983 NULL, &smb_fname->st);
1984 len = srvstr_push(base_data, flags2, p,
1985 fname, PTR_DIFF(end_data, p),
1986 STR_TERMINATE);
1987 } else {
1988 DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
1989 p = store_file_unix_basic_info2(conn, p,
1990 NULL, &smb_fname->st);
1991 nameptr = p;
1992 p += 4;
1993 len = srvstr_push(base_data, flags2, p, fname,
1994 PTR_DIFF(end_data, p), 0);
1995 SIVAL(nameptr, 0, len);
1998 p += len;
2000 len = PTR_DIFF(p, pdata);
2001 pad = (len + (align-1)) & ~(align-1);
2003 * offset to the next entry, the caller
2004 * will overwrite it for the last entry
2005 * that's why we always include the padding
2007 SIVAL(pdata,0,pad);
2009 * set padding to zero
2011 if (do_pad) {
2012 memset(p, 0, pad - len);
2013 p = pdata + pad;
2014 } else {
2015 p = pdata + len;
2017 /* End of SMB_QUERY_FILE_UNIX_BASIC */
2019 break;
2021 default:
2022 return false;
2025 if (PTR_DIFF(p,pdata) > space_remaining) {
2026 *out_of_space = true;
2027 DEBUG(9,("smbd_marshall_dir_entry: out of space\n"));
2028 return false; /* Not finished - just out of space */
2031 /* Setup the last entry pointer, as an offset from base_data */
2032 *last_entry_off = PTR_DIFF(last_entry_ptr,base_data);
2033 /* Advance the data pointer to the next slot */
2034 *ppdata = p;
2036 return true;
2039 bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
2040 connection_struct *conn,
2041 struct dptr_struct *dirptr,
2042 uint16 flags2,
2043 const char *path_mask,
2044 uint32 dirtype,
2045 int info_level,
2046 int requires_resume_key,
2047 bool dont_descend,
2048 bool ask_sharemode,
2049 uint8_t align,
2050 bool do_pad,
2051 char **ppdata,
2052 char *base_data,
2053 char *end_data,
2054 int space_remaining,
2055 bool *out_of_space,
2056 bool *got_exact_match,
2057 int *_last_entry_off,
2058 struct ea_list *name_list)
2060 const char *p;
2061 const char *mask = NULL;
2062 long prev_dirpos = 0;
2063 uint32_t mode = 0;
2064 char *fname = NULL;
2065 struct smb_filename *smb_fname = NULL;
2066 struct smbd_dirptr_lanman2_state state;
2067 bool ok;
2068 uint64_t last_entry_off = 0;
2070 ZERO_STRUCT(state);
2071 state.conn = conn;
2072 state.info_level = info_level;
2073 state.check_mangled_names = lp_manglednames(conn->params);
2074 state.has_wild = dptr_has_wild(dirptr);
2075 state.got_exact_match = false;
2077 *out_of_space = false;
2078 *got_exact_match = false;
2080 p = strrchr_m(path_mask,'/');
2081 if(p != NULL) {
2082 if(p[1] == '\0') {
2083 mask = "*.*";
2084 } else {
2085 mask = p+1;
2087 } else {
2088 mask = path_mask;
2091 ok = smbd_dirptr_get_entry(ctx,
2092 dirptr,
2093 mask,
2094 dirtype,
2095 dont_descend,
2096 ask_sharemode,
2097 smbd_dirptr_lanman2_match_fn,
2098 smbd_dirptr_lanman2_mode_fn,
2099 &state,
2100 &fname,
2101 &smb_fname,
2102 &mode,
2103 &prev_dirpos);
2104 if (!ok) {
2105 return false;
2108 *got_exact_match = state.got_exact_match;
2110 ok = smbd_marshall_dir_entry(ctx,
2111 conn,
2112 flags2,
2113 info_level,
2114 name_list,
2115 state.check_mangled_names,
2116 requires_resume_key,
2117 mode,
2118 fname,
2119 smb_fname,
2120 space_remaining,
2121 align,
2122 do_pad,
2123 base_data,
2124 ppdata,
2125 end_data,
2126 out_of_space,
2127 &last_entry_off);
2128 TALLOC_FREE(fname);
2129 TALLOC_FREE(smb_fname);
2130 if (*out_of_space) {
2131 dptr_SeekDir(dirptr, prev_dirpos);
2132 return false;
2134 if (!ok) {
2135 return false;
2138 *_last_entry_off = last_entry_off;
2139 return true;
2142 static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
2143 connection_struct *conn,
2144 struct dptr_struct *dirptr,
2145 uint16 flags2,
2146 const char *path_mask,
2147 uint32 dirtype,
2148 int info_level,
2149 bool requires_resume_key,
2150 bool dont_descend,
2151 bool ask_sharemode,
2152 char **ppdata,
2153 char *base_data,
2154 char *end_data,
2155 int space_remaining,
2156 bool *out_of_space,
2157 bool *got_exact_match,
2158 int *last_entry_off,
2159 struct ea_list *name_list)
2161 uint8_t align = 4;
2162 const bool do_pad = true;
2164 if (info_level >= 1 && info_level <= 3) {
2165 /* No alignment on earlier info levels. */
2166 align = 1;
2169 return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2,
2170 path_mask, dirtype, info_level,
2171 requires_resume_key, dont_descend, ask_sharemode,
2172 align, do_pad,
2173 ppdata, base_data, end_data,
2174 space_remaining,
2175 out_of_space, got_exact_match,
2176 last_entry_off, name_list);
2179 /****************************************************************************
2180 Reply to a TRANS2_FINDFIRST.
2181 ****************************************************************************/
2183 static void call_trans2findfirst(connection_struct *conn,
2184 struct smb_request *req,
2185 char **pparams, int total_params,
2186 char **ppdata, int total_data,
2187 unsigned int max_data_bytes)
2189 /* We must be careful here that we don't return more than the
2190 allowed number of data bytes. If this means returning fewer than
2191 maxentries then so be it. We assume that the redirector has
2192 enough room for the fixed number of parameter bytes it has
2193 requested. */
2194 struct smb_filename *smb_dname = NULL;
2195 char *params = *pparams;
2196 char *pdata = *ppdata;
2197 char *data_end;
2198 uint32 dirtype;
2199 int maxentries;
2200 uint16 findfirst_flags;
2201 bool close_after_first;
2202 bool close_if_end;
2203 bool requires_resume_key;
2204 int info_level;
2205 char *directory = NULL;
2206 char *mask = NULL;
2207 char *p;
2208 int last_entry_off=0;
2209 int dptr_num = -1;
2210 int numentries = 0;
2211 int i;
2212 bool finished = False;
2213 bool dont_descend = False;
2214 bool out_of_space = False;
2215 int space_remaining;
2216 bool mask_contains_wcard = False;
2217 struct ea_list *ea_list = NULL;
2218 NTSTATUS ntstatus = NT_STATUS_OK;
2219 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
2220 TALLOC_CTX *ctx = talloc_tos();
2221 struct dptr_struct *dirptr = NULL;
2222 struct smbd_server_connection *sconn = smbd_server_conn;
2224 if (total_params < 13) {
2225 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2226 goto out;
2229 dirtype = SVAL(params,0);
2230 maxentries = SVAL(params,2);
2231 findfirst_flags = SVAL(params,4);
2232 close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
2233 close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
2234 requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
2235 info_level = SVAL(params,6);
2237 DEBUG(3,("call_trans2findfirst: dirtype = %x, maxentries = %d, close_after_first=%d, \
2238 close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
2239 (unsigned int)dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
2240 info_level, max_data_bytes));
2242 if (!maxentries) {
2243 /* W2K3 seems to treat zero as 1. */
2244 maxentries = 1;
2247 switch (info_level) {
2248 case SMB_FIND_INFO_STANDARD:
2249 case SMB_FIND_EA_SIZE:
2250 case SMB_FIND_EA_LIST:
2251 case SMB_FIND_FILE_DIRECTORY_INFO:
2252 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
2253 case SMB_FIND_FILE_NAMES_INFO:
2254 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
2255 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
2256 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
2257 break;
2258 case SMB_FIND_FILE_UNIX:
2259 case SMB_FIND_FILE_UNIX_INFO2:
2260 /* Always use filesystem for UNIX mtime query. */
2261 ask_sharemode = false;
2262 if (!lp_unix_extensions()) {
2263 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2264 goto out;
2266 break;
2267 default:
2268 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2269 goto out;
2272 srvstr_get_path_wcard(ctx, params, req->flags2, &directory,
2273 params+12, total_params - 12,
2274 STR_TERMINATE, &ntstatus, &mask_contains_wcard);
2275 if (!NT_STATUS_IS_OK(ntstatus)) {
2276 reply_nterror(req, ntstatus);
2277 goto out;
2280 ntstatus = filename_convert(ctx, conn,
2281 req->flags2 & FLAGS2_DFS_PATHNAMES,
2282 directory,
2283 (UCF_SAVE_LCOMP |
2284 UCF_ALWAYS_ALLOW_WCARD_LCOMP),
2285 &mask_contains_wcard,
2286 &smb_dname);
2287 if (!NT_STATUS_IS_OK(ntstatus)) {
2288 if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
2289 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2290 ERRSRV, ERRbadpath);
2291 goto out;
2293 reply_nterror(req, ntstatus);
2294 goto out;
2297 mask = smb_dname->original_lcomp;
2299 directory = smb_dname->base_name;
2301 p = strrchr_m(directory,'/');
2302 if(p == NULL) {
2303 /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */
2304 if((directory[0] == '.') && (directory[1] == '\0')) {
2305 mask = talloc_strdup(ctx,"*");
2306 if (!mask) {
2307 reply_nterror(req, NT_STATUS_NO_MEMORY);
2308 goto out;
2310 mask_contains_wcard = True;
2312 directory = talloc_strdup(talloc_tos(), "./");
2313 if (!directory) {
2314 reply_nterror(req, NT_STATUS_NO_MEMORY);
2315 goto out;
2317 } else {
2318 *p = 0;
2321 DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
2323 if (info_level == SMB_FIND_EA_LIST) {
2324 uint32 ea_size;
2326 if (total_data < 4) {
2327 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2328 goto out;
2331 ea_size = IVAL(pdata,0);
2332 if (ea_size != total_data) {
2333 DEBUG(4,("call_trans2findfirst: Rejecting EA request with incorrect \
2334 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2335 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2336 goto out;
2339 if (!lp_ea_support(SNUM(conn))) {
2340 reply_doserror(req, ERRDOS, ERReasnotsupported);
2341 goto out;
2344 /* Pull out the list of names. */
2345 ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
2346 if (!ea_list) {
2347 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2348 goto out;
2352 *ppdata = (char *)SMB_REALLOC(
2353 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2354 if(*ppdata == NULL ) {
2355 reply_nterror(req, NT_STATUS_NO_MEMORY);
2356 goto out;
2358 pdata = *ppdata;
2359 data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2361 /* Realloc the params space */
2362 *pparams = (char *)SMB_REALLOC(*pparams, 10);
2363 if (*pparams == NULL) {
2364 reply_nterror(req, NT_STATUS_NO_MEMORY);
2365 goto out;
2367 params = *pparams;
2369 /* Save the wildcard match and attribs we are using on this directory -
2370 needed as lanman2 assumes these are being saved between calls */
2372 ntstatus = dptr_create(conn,
2373 directory,
2374 False,
2375 True,
2376 req->smbpid,
2377 mask,
2378 mask_contains_wcard,
2379 dirtype,
2380 &dirptr);
2382 if (!NT_STATUS_IS_OK(ntstatus)) {
2383 reply_nterror(req, ntstatus);
2384 goto out;
2387 dptr_num = dptr_dnum(dirptr);
2388 DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));
2390 /* Initialize per TRANS2_FIND_FIRST operation data */
2391 dptr_init_search_op(dirptr);
2393 /* We don't need to check for VOL here as this is returned by
2394 a different TRANS2 call. */
2396 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
2397 directory,lp_dontdescend(SNUM(conn))));
2398 if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
2399 dont_descend = True;
2401 p = pdata;
2402 space_remaining = max_data_bytes;
2403 out_of_space = False;
2405 for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
2406 bool got_exact_match = False;
2408 /* this is a heuristic to avoid seeking the dirptr except when
2409 absolutely necessary. It allows for a filename of about 40 chars */
2410 if (space_remaining < DIRLEN_GUESS && numentries > 0) {
2411 out_of_space = True;
2412 finished = False;
2413 } else {
2414 finished = !get_lanman2_dir_entry(ctx,
2415 conn,
2416 dirptr,
2417 req->flags2,
2418 mask,dirtype,info_level,
2419 requires_resume_key,dont_descend,
2420 ask_sharemode,
2421 &p,pdata,data_end,
2422 space_remaining, &out_of_space,
2423 &got_exact_match,
2424 &last_entry_off, ea_list);
2427 if (finished && out_of_space)
2428 finished = False;
2430 if (!finished && !out_of_space)
2431 numentries++;
2434 * As an optimisation if we know we aren't looking
2435 * for a wildcard name (ie. the name matches the wildcard exactly)
2436 * then we can finish on any (first) match.
2437 * This speeds up large directory searches. JRA.
2440 if(got_exact_match)
2441 finished = True;
2443 /* Ensure space_remaining never goes -ve. */
2444 if (PTR_DIFF(p,pdata) > max_data_bytes) {
2445 space_remaining = 0;
2446 out_of_space = true;
2447 } else {
2448 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
2452 /* Check if we can close the dirptr */
2453 if(close_after_first || (finished && close_if_end)) {
2454 DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
2455 dptr_close(sconn, &dptr_num);
2459 * If there are no matching entries we must return ERRDOS/ERRbadfile -
2460 * from observation of NT. NB. This changes to ERRDOS,ERRnofiles if
2461 * the protocol level is less than NT1. Tested with smbclient. JRA.
2462 * This should fix the OS/2 client bug #2335.
2465 if(numentries == 0) {
2466 dptr_close(sconn, &dptr_num);
2467 if (get_Protocol() < PROTOCOL_NT1) {
2468 reply_doserror(req, ERRDOS, ERRnofiles);
2469 goto out;
2470 } else {
2471 reply_botherror(req, NT_STATUS_NO_SUCH_FILE,
2472 ERRDOS, ERRbadfile);
2473 goto out;
2477 /* At this point pdata points to numentries directory entries. */
2479 /* Set up the return parameter block */
2480 SSVAL(params,0,dptr_num);
2481 SSVAL(params,2,numentries);
2482 SSVAL(params,4,finished);
2483 SSVAL(params,6,0); /* Never an EA error */
2484 SSVAL(params,8,last_entry_off);
2486 send_trans2_replies(conn, req, params, 10, pdata, PTR_DIFF(p,pdata),
2487 max_data_bytes);
2489 if ((! *directory) && dptr_path(sconn, dptr_num)) {
2490 directory = talloc_strdup(talloc_tos(),dptr_path(sconn, dptr_num));
2491 if (!directory) {
2492 reply_nterror(req, NT_STATUS_NO_MEMORY);
2496 DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
2497 smb_fn_name(req->cmd),
2498 mask, directory, dirtype, numentries ) );
2501 * Force a name mangle here to ensure that the
2502 * mask as an 8.3 name is top of the mangled cache.
2503 * The reasons for this are subtle. Don't remove
2504 * this code unless you know what you are doing
2505 * (see PR#13758). JRA.
2508 if(!mangle_is_8_3_wildcards( mask, False, conn->params)) {
2509 char mangled_name[13];
2510 name_to_8_3(mask, mangled_name, True, conn->params);
2512 out:
2513 TALLOC_FREE(smb_dname);
2514 return;
2517 /****************************************************************************
2518 Reply to a TRANS2_FINDNEXT.
2519 ****************************************************************************/
2521 static void call_trans2findnext(connection_struct *conn,
2522 struct smb_request *req,
2523 char **pparams, int total_params,
2524 char **ppdata, int total_data,
2525 unsigned int max_data_bytes)
2527 /* We must be careful here that we don't return more than the
2528 allowed number of data bytes. If this means returning fewer than
2529 maxentries then so be it. We assume that the redirector has
2530 enough room for the fixed number of parameter bytes it has
2531 requested. */
2532 char *params = *pparams;
2533 char *pdata = *ppdata;
2534 char *data_end;
2535 int dptr_num;
2536 int maxentries;
2537 uint16 info_level;
2538 uint32 resume_key;
2539 uint16 findnext_flags;
2540 bool close_after_request;
2541 bool close_if_end;
2542 bool requires_resume_key;
2543 bool continue_bit;
2544 bool mask_contains_wcard = False;
2545 char *resume_name = NULL;
2546 const char *mask = NULL;
2547 const char *directory = NULL;
2548 char *p = NULL;
2549 uint16 dirtype;
2550 int numentries = 0;
2551 int i, last_entry_off=0;
2552 bool finished = False;
2553 bool dont_descend = False;
2554 bool out_of_space = False;
2555 int space_remaining;
2556 struct ea_list *ea_list = NULL;
2557 NTSTATUS ntstatus = NT_STATUS_OK;
2558 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
2559 TALLOC_CTX *ctx = talloc_tos();
2560 struct dptr_struct *dirptr;
2561 struct smbd_server_connection *sconn = smbd_server_conn;
2563 if (total_params < 13) {
2564 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2565 return;
2568 dptr_num = SVAL(params,0);
2569 maxentries = SVAL(params,2);
2570 info_level = SVAL(params,4);
2571 resume_key = IVAL(params,6);
2572 findnext_flags = SVAL(params,10);
2573 close_after_request = (findnext_flags & FLAG_TRANS2_FIND_CLOSE);
2574 close_if_end = (findnext_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
2575 requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
2576 continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE);
2578 if (!continue_bit) {
2579 /* We only need resume_name if continue_bit is zero. */
2580 srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name,
2581 params+12,
2582 total_params - 12, STR_TERMINATE, &ntstatus,
2583 &mask_contains_wcard);
2584 if (!NT_STATUS_IS_OK(ntstatus)) {
2585 /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
2586 complain (it thinks we're asking for the directory above the shared
2587 path or an invalid name). Catch this as the resume name is only compared, never used in
2588 a file access. JRA. */
2589 srvstr_pull_talloc(ctx, params, req->flags2,
2590 &resume_name, params+12,
2591 total_params - 12,
2592 STR_TERMINATE);
2594 if (!resume_name || !(ISDOT(resume_name) || ISDOTDOT(resume_name))) {
2595 reply_nterror(req, ntstatus);
2596 return;
2601 DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \
2602 close_after_request=%d, close_if_end = %d requires_resume_key = %d \
2603 resume_key = %d resume name = %s continue=%d level = %d\n",
2604 dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end,
2605 requires_resume_key, resume_key,
2606 resume_name ? resume_name : "(NULL)", continue_bit, info_level));
2608 if (!maxentries) {
2609 /* W2K3 seems to treat zero as 1. */
2610 maxentries = 1;
2613 switch (info_level) {
2614 case SMB_FIND_INFO_STANDARD:
2615 case SMB_FIND_EA_SIZE:
2616 case SMB_FIND_EA_LIST:
2617 case SMB_FIND_FILE_DIRECTORY_INFO:
2618 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
2619 case SMB_FIND_FILE_NAMES_INFO:
2620 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
2621 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
2622 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
2623 break;
2624 case SMB_FIND_FILE_UNIX:
2625 case SMB_FIND_FILE_UNIX_INFO2:
2626 /* Always use filesystem for UNIX mtime query. */
2627 ask_sharemode = false;
2628 if (!lp_unix_extensions()) {
2629 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2630 return;
2632 break;
2633 default:
2634 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2635 return;
2638 if (info_level == SMB_FIND_EA_LIST) {
2639 uint32 ea_size;
2641 if (total_data < 4) {
2642 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2643 return;
2646 ea_size = IVAL(pdata,0);
2647 if (ea_size != total_data) {
2648 DEBUG(4,("call_trans2findnext: Rejecting EA request with incorrect \
2649 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2650 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2651 return;
2654 if (!lp_ea_support(SNUM(conn))) {
2655 reply_doserror(req, ERRDOS, ERReasnotsupported);
2656 return;
2659 /* Pull out the list of names. */
2660 ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
2661 if (!ea_list) {
2662 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2663 return;
2667 *ppdata = (char *)SMB_REALLOC(
2668 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2669 if(*ppdata == NULL) {
2670 reply_nterror(req, NT_STATUS_NO_MEMORY);
2671 return;
2674 pdata = *ppdata;
2675 data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2677 /* Realloc the params space */
2678 *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD);
2679 if(*pparams == NULL ) {
2680 reply_nterror(req, NT_STATUS_NO_MEMORY);
2681 return;
2684 params = *pparams;
2686 /* Check that the dptr is valid */
2687 if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) {
2688 reply_doserror(req, ERRDOS, ERRnofiles);
2689 return;
2692 directory = dptr_path(sconn, dptr_num);
2694 /* Get the wildcard mask from the dptr */
2695 if((p = dptr_wcard(sconn, dptr_num))== NULL) {
2696 DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
2697 reply_doserror(req, ERRDOS, ERRnofiles);
2698 return;
2701 mask = p;
2703 /* Get the attr mask from the dptr */
2704 dirtype = dptr_attr(sconn, dptr_num);
2706 DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld)\n",
2707 dptr_num, mask, dirtype,
2708 (long)dirptr,
2709 dptr_TellDir(dirptr)));
2711 /* Initialize per TRANS2_FIND_NEXT operation data */
2712 dptr_init_search_op(dirptr);
2714 /* We don't need to check for VOL here as this is returned by
2715 a different TRANS2 call. */
2717 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
2718 directory,lp_dontdescend(SNUM(conn))));
2719 if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
2720 dont_descend = True;
2722 p = pdata;
2723 space_remaining = max_data_bytes;
2724 out_of_space = False;
2727 * Seek to the correct position. We no longer use the resume key but
2728 * depend on the last file name instead.
2731 if(!continue_bit && resume_name && *resume_name) {
2732 SMB_STRUCT_STAT st;
2734 long current_pos = 0;
2736 * Remember, name_to_8_3 is called by
2737 * get_lanman2_dir_entry(), so the resume name
2738 * could be mangled. Ensure we check the unmangled name.
2741 if (mangle_is_mangled(resume_name, conn->params)) {
2742 char *new_resume_name = NULL;
2743 mangle_lookup_name_from_8_3(ctx,
2744 resume_name,
2745 &new_resume_name,
2746 conn->params);
2747 if (new_resume_name) {
2748 resume_name = new_resume_name;
2753 * Fix for NT redirector problem triggered by resume key indexes
2754 * changing between directory scans. We now return a resume key of 0
2755 * and instead look for the filename to continue from (also given
2756 * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
2757 * findfirst/findnext (as is usual) then the directory pointer
2758 * should already be at the correct place.
2761 finished = !dptr_SearchDir(dirptr, resume_name, &current_pos, &st);
2762 } /* end if resume_name && !continue_bit */
2764 for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
2765 bool got_exact_match = False;
2767 /* this is a heuristic to avoid seeking the dirptr except when
2768 absolutely necessary. It allows for a filename of about 40 chars */
2769 if (space_remaining < DIRLEN_GUESS && numentries > 0) {
2770 out_of_space = True;
2771 finished = False;
2772 } else {
2773 finished = !get_lanman2_dir_entry(ctx,
2774 conn,
2775 dirptr,
2776 req->flags2,
2777 mask,dirtype,info_level,
2778 requires_resume_key,dont_descend,
2779 ask_sharemode,
2780 &p,pdata,data_end,
2781 space_remaining, &out_of_space,
2782 &got_exact_match,
2783 &last_entry_off, ea_list);
2786 if (finished && out_of_space)
2787 finished = False;
2789 if (!finished && !out_of_space)
2790 numentries++;
2793 * As an optimisation if we know we aren't looking
2794 * for a wildcard name (ie. the name matches the wildcard exactly)
2795 * then we can finish on any (first) match.
2796 * This speeds up large directory searches. JRA.
2799 if(got_exact_match)
2800 finished = True;
2802 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
2805 DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
2806 smb_fn_name(req->cmd),
2807 mask, directory, dirtype, numentries ) );
2809 /* Check if we can close the dirptr */
2810 if(close_after_request || (finished && close_if_end)) {
2811 DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
2812 dptr_close(sconn, &dptr_num); /* This frees up the saved mask */
2815 /* Set up the return parameter block */
2816 SSVAL(params,0,numentries);
2817 SSVAL(params,2,finished);
2818 SSVAL(params,4,0); /* Never an EA error */
2819 SSVAL(params,6,last_entry_off);
2821 send_trans2_replies(conn, req, params, 8, pdata, PTR_DIFF(p,pdata),
2822 max_data_bytes);
2824 return;
2827 unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
2829 E_md4hash(lp_servicename(SNUM(conn)),objid);
2830 return objid;
2833 static void samba_extended_info_version(struct smb_extended_info *extended_info)
2835 SMB_ASSERT(extended_info != NULL);
2837 extended_info->samba_magic = SAMBA_EXTENDED_INFO_MAGIC;
2838 extended_info->samba_version = ((SAMBA_VERSION_MAJOR & 0xff) << 24)
2839 | ((SAMBA_VERSION_MINOR & 0xff) << 16)
2840 | ((SAMBA_VERSION_RELEASE & 0xff) << 8);
2841 #ifdef SAMBA_VERSION_REVISION
2842 extended_info->samba_version |= (tolower(*SAMBA_VERSION_REVISION) - 'a' + 1) & 0xff;
2843 #endif
2844 extended_info->samba_subversion = 0;
2845 #ifdef SAMBA_VERSION_RC_RELEASE
2846 extended_info->samba_subversion |= (SAMBA_VERSION_RC_RELEASE & 0xff) << 24;
2847 #else
2848 #ifdef SAMBA_VERSION_PRE_RELEASE
2849 extended_info->samba_subversion |= (SAMBA_VERSION_PRE_RELEASE & 0xff) << 16;
2850 #endif
2851 #endif
2852 #ifdef SAMBA_VERSION_VENDOR_PATCH
2853 extended_info->samba_subversion |= (SAMBA_VERSION_VENDOR_PATCH & 0xffff);
2854 #endif
2855 extended_info->samba_gitcommitdate = 0;
2856 #ifdef SAMBA_VERSION_GIT_COMMIT_TIME
2857 unix_to_nt_time(&extended_info->samba_gitcommitdate, SAMBA_VERSION_GIT_COMMIT_TIME);
2858 #endif
2860 memset(extended_info->samba_version_string, 0,
2861 sizeof(extended_info->samba_version_string));
2863 snprintf (extended_info->samba_version_string,
2864 sizeof(extended_info->samba_version_string),
2865 "%s", samba_version_string());
2868 NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
2869 TALLOC_CTX *mem_ctx,
2870 uint16_t info_level,
2871 uint16_t flags2,
2872 unsigned int max_data_bytes,
2873 char **ppdata,
2874 int *ret_data_len)
2876 char *pdata, *end_data;
2877 int data_len = 0, len;
2878 const char *vname = volume_label(SNUM(conn));
2879 int snum = SNUM(conn);
2880 char *fstype = lp_fstype(SNUM(conn));
2881 uint32 additional_flags = 0;
2882 struct smb_filename smb_fname_dot;
2883 SMB_STRUCT_STAT st;
2885 if (IS_IPC(conn)) {
2886 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
2887 DEBUG(0,("smbd_do_qfsinfo: not an allowed "
2888 "info level (0x%x) on IPC$.\n",
2889 (unsigned int)info_level));
2890 return NT_STATUS_ACCESS_DENIED;
2894 DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level));
2896 ZERO_STRUCT(smb_fname_dot);
2897 smb_fname_dot.base_name = discard_const_p(char, ".");
2899 if(SMB_VFS_STAT(conn, &smb_fname_dot) != 0) {
2900 DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
2901 return map_nt_error_from_unix(errno);
2904 st = smb_fname_dot.st;
2906 *ppdata = (char *)SMB_REALLOC(
2907 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2908 if (*ppdata == NULL) {
2909 return NT_STATUS_NO_MEMORY;
2912 pdata = *ppdata;
2913 memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2914 end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2916 switch (info_level) {
2917 case SMB_INFO_ALLOCATION:
2919 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
2920 data_len = 18;
2921 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
2922 return map_nt_error_from_unix(errno);
2925 block_size = lp_block_size(snum);
2926 if (bsize < block_size) {
2927 uint64_t factor = block_size/bsize;
2928 bsize = block_size;
2929 dsize /= factor;
2930 dfree /= factor;
2932 if (bsize > block_size) {
2933 uint64_t factor = bsize/block_size;
2934 bsize = block_size;
2935 dsize *= factor;
2936 dfree *= factor;
2938 bytes_per_sector = 512;
2939 sectors_per_unit = bsize/bytes_per_sector;
2941 DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
2942 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
2943 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2945 SIVAL(pdata,l1_idFileSystem,st.st_ex_dev);
2946 SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
2947 SIVAL(pdata,l1_cUnit,dsize);
2948 SIVAL(pdata,l1_cUnitAvail,dfree);
2949 SSVAL(pdata,l1_cbSector,bytes_per_sector);
2950 break;
2953 case SMB_INFO_VOLUME:
2954 /* Return volume name */
2956 * Add volume serial number - hash of a combination of
2957 * the called hostname and the service name.
2959 SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(get_local_machine_name())<<16) );
2961 * Win2k3 and previous mess this up by sending a name length
2962 * one byte short. I believe only older clients (OS/2 Win9x) use
2963 * this call so try fixing this by adding a terminating null to
2964 * the pushed string. The change here was adding the STR_TERMINATE. JRA.
2966 len = srvstr_push(
2967 pdata, flags2,
2968 pdata+l2_vol_szVolLabel, vname,
2969 PTR_DIFF(end_data, pdata+l2_vol_szVolLabel),
2970 STR_NOALIGN|STR_TERMINATE);
2971 SCVAL(pdata,l2_vol_cch,len);
2972 data_len = l2_vol_szVolLabel + len;
2973 DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %d, name = %s\n",
2974 (unsigned)convert_timespec_to_time_t(st.st_ex_ctime),
2975 len, vname));
2976 break;
2978 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2979 case SMB_FS_ATTRIBUTE_INFORMATION:
2981 additional_flags = 0;
2982 #if defined(HAVE_SYS_QUOTAS)
2983 additional_flags |= FILE_VOLUME_QUOTAS;
2984 #endif
2986 if(lp_nt_acl_support(SNUM(conn))) {
2987 additional_flags |= FILE_PERSISTENT_ACLS;
2990 /* Capabilities are filled in at connection time through STATVFS call */
2991 additional_flags |= conn->fs_capabilities;
2992 additional_flags |= lp_parm_int(conn->params->service,
2993 "share", "fake_fscaps",
2996 SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
2997 FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
2998 additional_flags); /* FS ATTRIBUTES */
3000 SIVAL(pdata,4,255); /* Max filename component length */
3001 /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
3002 and will think we can't do long filenames */
3003 len = srvstr_push(pdata, flags2, pdata+12, fstype,
3004 PTR_DIFF(end_data, pdata+12),
3005 STR_UNICODE);
3006 SIVAL(pdata,8,len);
3007 data_len = 12 + len;
3008 break;
3010 case SMB_QUERY_FS_LABEL_INFO:
3011 case SMB_FS_LABEL_INFORMATION:
3012 len = srvstr_push(pdata, flags2, pdata+4, vname,
3013 PTR_DIFF(end_data, pdata+4), 0);
3014 data_len = 4 + len;
3015 SIVAL(pdata,0,len);
3016 break;
3018 case SMB_QUERY_FS_VOLUME_INFO:
3019 case SMB_FS_VOLUME_INFORMATION:
3022 * Add volume serial number - hash of a combination of
3023 * the called hostname and the service name.
3025 SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^
3026 (str_checksum(get_local_machine_name())<<16));
3028 /* Max label len is 32 characters. */
3029 len = srvstr_push(pdata, flags2, pdata+18, vname,
3030 PTR_DIFF(end_data, pdata+18),
3031 STR_UNICODE);
3032 SIVAL(pdata,12,len);
3033 data_len = 18+len;
3035 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
3036 (int)strlen(vname),vname, lp_servicename(snum)));
3037 break;
3039 case SMB_QUERY_FS_SIZE_INFO:
3040 case SMB_FS_SIZE_INFORMATION:
3042 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
3043 data_len = 24;
3044 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
3045 return map_nt_error_from_unix(errno);
3047 block_size = lp_block_size(snum);
3048 if (bsize < block_size) {
3049 uint64_t factor = block_size/bsize;
3050 bsize = block_size;
3051 dsize /= factor;
3052 dfree /= factor;
3054 if (bsize > block_size) {
3055 uint64_t factor = bsize/block_size;
3056 bsize = block_size;
3057 dsize *= factor;
3058 dfree *= factor;
3060 bytes_per_sector = 512;
3061 sectors_per_unit = bsize/bytes_per_sector;
3062 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
3063 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
3064 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
3065 SBIG_UINT(pdata,0,dsize);
3066 SBIG_UINT(pdata,8,dfree);
3067 SIVAL(pdata,16,sectors_per_unit);
3068 SIVAL(pdata,20,bytes_per_sector);
3069 break;
3072 case SMB_FS_FULL_SIZE_INFORMATION:
3074 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
3075 data_len = 32;
3076 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
3077 return map_nt_error_from_unix(errno);
3079 block_size = lp_block_size(snum);
3080 if (bsize < block_size) {
3081 uint64_t factor = block_size/bsize;
3082 bsize = block_size;
3083 dsize /= factor;
3084 dfree /= factor;
3086 if (bsize > block_size) {
3087 uint64_t factor = bsize/block_size;
3088 bsize = block_size;
3089 dsize *= factor;
3090 dfree *= factor;
3092 bytes_per_sector = 512;
3093 sectors_per_unit = bsize/bytes_per_sector;
3094 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
3095 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
3096 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
3097 SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
3098 SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
3099 SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
3100 SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
3101 SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
3102 break;
3105 case SMB_QUERY_FS_DEVICE_INFO:
3106 case SMB_FS_DEVICE_INFORMATION:
3107 data_len = 8;
3108 SIVAL(pdata,0,0); /* dev type */
3109 SIVAL(pdata,4,0); /* characteristics */
3110 break;
3112 #ifdef HAVE_SYS_QUOTAS
3113 case SMB_FS_QUOTA_INFORMATION:
3115 * what we have to send --metze:
3117 * Unknown1: 24 NULL bytes
3118 * Soft Quota Treshold: 8 bytes seems like uint64_t or so
3119 * Hard Quota Limit: 8 bytes seems like uint64_t or so
3120 * Quota Flags: 2 byte :
3121 * Unknown3: 6 NULL bytes
3123 * 48 bytes total
3125 * details for Quota Flags:
3127 * 0x0020 Log Limit: log if the user exceeds his Hard Quota
3128 * 0x0010 Log Warn: log if the user exceeds his Soft Quota
3129 * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
3130 * 0x0001 Enable Quotas: enable quota for this fs
3134 /* we need to fake up a fsp here,
3135 * because its not send in this call
3137 files_struct fsp;
3138 SMB_NTQUOTA_STRUCT quotas;
3140 ZERO_STRUCT(fsp);
3141 ZERO_STRUCT(quotas);
3143 fsp.conn = conn;
3144 fsp.fnum = -1;
3146 /* access check */
3147 if (conn->server_info->utok.uid != sec_initial_uid()) {
3148 DEBUG(0,("set_user_quota: access_denied "
3149 "service [%s] user [%s]\n",
3150 lp_servicename(SNUM(conn)),
3151 conn->server_info->unix_name));
3152 return NT_STATUS_ACCESS_DENIED;
3155 if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
3156 DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3157 return map_nt_error_from_unix(errno);
3160 data_len = 48;
3162 DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",
3163 lp_servicename(SNUM(conn))));
3165 /* Unknown1 24 NULL bytes*/
3166 SBIG_UINT(pdata,0,(uint64_t)0);
3167 SBIG_UINT(pdata,8,(uint64_t)0);
3168 SBIG_UINT(pdata,16,(uint64_t)0);
3170 /* Default Soft Quota 8 bytes */
3171 SBIG_UINT(pdata,24,quotas.softlim);
3173 /* Default Hard Quota 8 bytes */
3174 SBIG_UINT(pdata,32,quotas.hardlim);
3176 /* Quota flag 2 bytes */
3177 SSVAL(pdata,40,quotas.qflags);
3179 /* Unknown3 6 NULL bytes */
3180 SSVAL(pdata,42,0);
3181 SIVAL(pdata,44,0);
3183 break;
3185 #endif /* HAVE_SYS_QUOTAS */
3186 case SMB_FS_OBJECTID_INFORMATION:
3188 unsigned char objid[16];
3189 struct smb_extended_info extended_info;
3190 memcpy(pdata,create_volume_objectid(conn, objid),16);
3191 samba_extended_info_version (&extended_info);
3192 SIVAL(pdata,16,extended_info.samba_magic);
3193 SIVAL(pdata,20,extended_info.samba_version);
3194 SIVAL(pdata,24,extended_info.samba_subversion);
3195 SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
3196 memcpy(pdata+36,extended_info.samba_version_string,28);
3197 data_len = 64;
3198 break;
3202 * Query the version and capabilities of the CIFS UNIX extensions
3203 * in use.
3206 case SMB_QUERY_CIFS_UNIX_INFO:
3208 bool large_write = lp_min_receive_file_size() &&
3209 !srv_is_signing_active(smbd_server_conn);
3210 bool large_read = !srv_is_signing_active(smbd_server_conn);
3211 int encrypt_caps = 0;
3213 if (!lp_unix_extensions()) {
3214 return NT_STATUS_INVALID_LEVEL;
3217 switch (conn->encrypt_level) {
3218 case 0:
3219 encrypt_caps = 0;
3220 break;
3221 case 1:
3222 case Auto:
3223 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
3224 break;
3225 case Required:
3226 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
3227 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
3228 large_write = false;
3229 large_read = false;
3230 break;
3233 data_len = 12;
3234 SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
3235 SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
3237 /* We have POSIX ACLs, pathname, encryption,
3238 * large read/write, and locking capability. */
3240 SBIG_UINT(pdata,4,((uint64_t)(
3241 CIFS_UNIX_POSIX_ACLS_CAP|
3242 CIFS_UNIX_POSIX_PATHNAMES_CAP|
3243 CIFS_UNIX_FCNTL_LOCKS_CAP|
3244 CIFS_UNIX_EXTATTR_CAP|
3245 CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
3246 encrypt_caps|
3247 (large_read ? CIFS_UNIX_LARGE_READ_CAP : 0) |
3248 (large_write ?
3249 CIFS_UNIX_LARGE_WRITE_CAP : 0))));
3250 break;
3253 case SMB_QUERY_POSIX_FS_INFO:
3255 int rc;
3256 vfs_statvfs_struct svfs;
3258 if (!lp_unix_extensions()) {
3259 return NT_STATUS_INVALID_LEVEL;
3262 rc = SMB_VFS_STATVFS(conn, ".", &svfs);
3264 if (!rc) {
3265 data_len = 56;
3266 SIVAL(pdata,0,svfs.OptimalTransferSize);
3267 SIVAL(pdata,4,svfs.BlockSize);
3268 SBIG_UINT(pdata,8,svfs.TotalBlocks);
3269 SBIG_UINT(pdata,16,svfs.BlocksAvail);
3270 SBIG_UINT(pdata,24,svfs.UserBlocksAvail);
3271 SBIG_UINT(pdata,32,svfs.TotalFileNodes);
3272 SBIG_UINT(pdata,40,svfs.FreeFileNodes);
3273 SBIG_UINT(pdata,48,svfs.FsIdentifier);
3274 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
3275 #ifdef EOPNOTSUPP
3276 } else if (rc == EOPNOTSUPP) {
3277 return NT_STATUS_INVALID_LEVEL;
3278 #endif /* EOPNOTSUPP */
3279 } else {
3280 DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3281 return NT_STATUS_DOS(ERRSRV, ERRerror);
3283 break;
3286 case SMB_QUERY_POSIX_WHOAMI:
3288 uint32_t flags = 0;
3289 uint32_t sid_bytes;
3290 int i;
3292 if (!lp_unix_extensions()) {
3293 return NT_STATUS_INVALID_LEVEL;
3296 if (max_data_bytes < 40) {
3297 return NT_STATUS_BUFFER_TOO_SMALL;
3300 /* We ARE guest if global_sid_Builtin_Guests is
3301 * in our list of SIDs.
3303 if (nt_token_check_sid(&global_sid_Builtin_Guests,
3304 conn->server_info->ptok)) {
3305 flags |= SMB_WHOAMI_GUEST;
3308 /* We are NOT guest if global_sid_Authenticated_Users
3309 * is in our list of SIDs.
3311 if (nt_token_check_sid(&global_sid_Authenticated_Users,
3312 conn->server_info->ptok)) {
3313 flags &= ~SMB_WHOAMI_GUEST;
3316 /* NOTE: 8 bytes for UID/GID, irrespective of native
3317 * platform size. This matches
3318 * SMB_QUERY_FILE_UNIX_BASIC and friends.
3320 data_len = 4 /* flags */
3321 + 4 /* flag mask */
3322 + 8 /* uid */
3323 + 8 /* gid */
3324 + 4 /* ngroups */
3325 + 4 /* num_sids */
3326 + 4 /* SID bytes */
3327 + 4 /* pad/reserved */
3328 + (conn->server_info->utok.ngroups * 8)
3329 /* groups list */
3330 + (conn->server_info->ptok->num_sids *
3331 SID_MAX_SIZE)
3332 /* SID list */;
3334 SIVAL(pdata, 0, flags);
3335 SIVAL(pdata, 4, SMB_WHOAMI_MASK);
3336 SBIG_UINT(pdata, 8,
3337 (uint64_t)conn->server_info->utok.uid);
3338 SBIG_UINT(pdata, 16,
3339 (uint64_t)conn->server_info->utok.gid);
3342 if (data_len >= max_data_bytes) {
3343 /* Potential overflow, skip the GIDs and SIDs. */
3345 SIVAL(pdata, 24, 0); /* num_groups */
3346 SIVAL(pdata, 28, 0); /* num_sids */
3347 SIVAL(pdata, 32, 0); /* num_sid_bytes */
3348 SIVAL(pdata, 36, 0); /* reserved */
3350 data_len = 40;
3351 break;
3354 SIVAL(pdata, 24, conn->server_info->utok.ngroups);
3355 SIVAL(pdata, 28, conn->server_info->num_sids);
3357 /* We walk the SID list twice, but this call is fairly
3358 * infrequent, and I don't expect that it's performance
3359 * sensitive -- jpeach
3361 for (i = 0, sid_bytes = 0;
3362 i < conn->server_info->ptok->num_sids; ++i) {
3363 sid_bytes += ndr_size_dom_sid(
3364 &conn->server_info->ptok->user_sids[i],
3365 NULL,
3369 /* SID list byte count */
3370 SIVAL(pdata, 32, sid_bytes);
3372 /* 4 bytes pad/reserved - must be zero */
3373 SIVAL(pdata, 36, 0);
3374 data_len = 40;
3376 /* GID list */
3377 for (i = 0; i < conn->server_info->utok.ngroups; ++i) {
3378 SBIG_UINT(pdata, data_len,
3379 (uint64_t)conn->server_info->utok.groups[i]);
3380 data_len += 8;
3383 /* SID list */
3384 for (i = 0;
3385 i < conn->server_info->ptok->num_sids; ++i) {
3386 int sid_len = ndr_size_dom_sid(
3387 &conn->server_info->ptok->user_sids[i],
3388 NULL,
3391 sid_linearize(pdata + data_len, sid_len,
3392 &conn->server_info->ptok->user_sids[i]);
3393 data_len += sid_len;
3396 break;
3399 case SMB_MAC_QUERY_FS_INFO:
3401 * Thursby MAC extension... ONLY on NTFS filesystems
3402 * once we do streams then we don't need this
3404 if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
3405 data_len = 88;
3406 SIVAL(pdata,84,0x100); /* Don't support mac... */
3407 break;
3409 /* drop through */
3410 default:
3411 return NT_STATUS_INVALID_LEVEL;
3414 *ret_data_len = data_len;
3415 return NT_STATUS_OK;
3418 /****************************************************************************
3419 Reply to a TRANS2_QFSINFO (query filesystem info).
3420 ****************************************************************************/
3422 static void call_trans2qfsinfo(connection_struct *conn,
3423 struct smb_request *req,
3424 char **pparams, int total_params,
3425 char **ppdata, int total_data,
3426 unsigned int max_data_bytes)
3428 char *params = *pparams;
3429 uint16_t info_level;
3430 int data_len = 0;
3431 NTSTATUS status;
3433 if (total_params < 2) {
3434 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3435 return;
3438 info_level = SVAL(params,0);
3440 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
3441 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
3442 DEBUG(0,("call_trans2qfsinfo: encryption required "
3443 "and info level 0x%x sent.\n",
3444 (unsigned int)info_level));
3445 exit_server_cleanly("encryption required "
3446 "on connection");
3447 return;
3451 DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
3453 status = smbd_do_qfsinfo(conn, req,
3454 info_level,
3455 req->flags2,
3456 max_data_bytes,
3457 ppdata, &data_len);
3458 if (!NT_STATUS_IS_OK(status)) {
3459 reply_nterror(req, status);
3460 return;
3463 send_trans2_replies(conn, req, params, 0, *ppdata, data_len,
3464 max_data_bytes);
3466 DEBUG( 4, ( "%s info_level = %d\n",
3467 smb_fn_name(req->cmd), info_level) );
3469 return;
3472 /****************************************************************************
3473 Reply to a TRANS2_SETFSINFO (set filesystem info).
3474 ****************************************************************************/
3476 static void call_trans2setfsinfo(connection_struct *conn,
3477 struct smb_request *req,
3478 char **pparams, int total_params,
3479 char **ppdata, int total_data,
3480 unsigned int max_data_bytes)
3482 char *pdata = *ppdata;
3483 char *params = *pparams;
3484 uint16 info_level;
3486 DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",lp_servicename(SNUM(conn))));
3488 /* */
3489 if (total_params < 4) {
3490 DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
3491 total_params));
3492 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3493 return;
3496 info_level = SVAL(params,2);
3498 if (IS_IPC(conn)) {
3499 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION &&
3500 info_level != SMB_SET_CIFS_UNIX_INFO) {
3501 DEBUG(0,("call_trans2setfsinfo: not an allowed "
3502 "info level (0x%x) on IPC$.\n",
3503 (unsigned int)info_level));
3504 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3505 return;
3509 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
3510 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION) {
3511 DEBUG(0,("call_trans2setfsinfo: encryption required "
3512 "and info level 0x%x sent.\n",
3513 (unsigned int)info_level));
3514 exit_server_cleanly("encryption required "
3515 "on connection");
3516 return;
3520 switch(info_level) {
3521 case SMB_SET_CIFS_UNIX_INFO:
3523 uint16 client_unix_major;
3524 uint16 client_unix_minor;
3525 uint32 client_unix_cap_low;
3526 uint32 client_unix_cap_high;
3528 if (!lp_unix_extensions()) {
3529 reply_nterror(req,
3530 NT_STATUS_INVALID_LEVEL);
3531 return;
3534 /* There should be 12 bytes of capabilities set. */
3535 if (total_data < 8) {
3536 reply_nterror(
3537 req,
3538 NT_STATUS_INVALID_PARAMETER);
3539 return;
3541 client_unix_major = SVAL(pdata,0);
3542 client_unix_minor = SVAL(pdata,2);
3543 client_unix_cap_low = IVAL(pdata,4);
3544 client_unix_cap_high = IVAL(pdata,8);
3545 /* Just print these values for now. */
3546 DEBUG(10,("call_trans2setfsinfo: set unix info. major = %u, minor = %u \
3547 cap_low = 0x%x, cap_high = 0x%x\n",
3548 (unsigned int)client_unix_major,
3549 (unsigned int)client_unix_minor,
3550 (unsigned int)client_unix_cap_low,
3551 (unsigned int)client_unix_cap_high ));
3553 /* Here is where we must switch to posix pathname processing... */
3554 if (client_unix_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3555 lp_set_posix_pathnames();
3556 mangle_change_to_posix();
3559 if ((client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) &&
3560 !(client_unix_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) {
3561 /* Client that knows how to do posix locks,
3562 * but not posix open/mkdir operations. Set a
3563 * default type for read/write checks. */
3565 lp_set_posix_default_cifsx_readwrite_locktype(POSIX_LOCK);
3568 break;
3571 case SMB_REQUEST_TRANSPORT_ENCRYPTION:
3573 NTSTATUS status;
3574 size_t param_len = 0;
3575 size_t data_len = total_data;
3577 if (!lp_unix_extensions()) {
3578 reply_nterror(
3579 req,
3580 NT_STATUS_INVALID_LEVEL);
3581 return;
3584 if (lp_smb_encrypt(SNUM(conn)) == false) {
3585 reply_nterror(
3586 req,
3587 NT_STATUS_NOT_SUPPORTED);
3588 return;
3591 DEBUG( 4,("call_trans2setfsinfo: "
3592 "request transport encryption.\n"));
3594 status = srv_request_encryption_setup(conn,
3595 (unsigned char **)ppdata,
3596 &data_len,
3597 (unsigned char **)pparams,
3598 &param_len);
3600 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
3601 !NT_STATUS_IS_OK(status)) {
3602 reply_nterror(req, status);
3603 return;
3606 send_trans2_replies(conn, req,
3607 *pparams,
3608 param_len,
3609 *ppdata,
3610 data_len,
3611 max_data_bytes);
3613 if (NT_STATUS_IS_OK(status)) {
3614 /* Server-side transport
3615 * encryption is now *on*. */
3616 status = srv_encryption_start(conn);
3617 if (!NT_STATUS_IS_OK(status)) {
3618 exit_server_cleanly(
3619 "Failure in setting "
3620 "up encrypted transport");
3623 return;
3626 case SMB_FS_QUOTA_INFORMATION:
3628 files_struct *fsp = NULL;
3629 SMB_NTQUOTA_STRUCT quotas;
3631 ZERO_STRUCT(quotas);
3633 /* access check */
3634 if ((conn->server_info->utok.uid != sec_initial_uid())
3635 ||!CAN_WRITE(conn)) {
3636 DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
3637 lp_servicename(SNUM(conn)),
3638 conn->server_info->unix_name));
3639 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3640 return;
3643 /* note: normaly there're 48 bytes,
3644 * but we didn't use the last 6 bytes for now
3645 * --metze
3647 fsp = file_fsp(req, SVAL(params,0));
3649 if (!check_fsp_ntquota_handle(conn, req,
3650 fsp)) {
3651 DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
3652 reply_nterror(
3653 req, NT_STATUS_INVALID_HANDLE);
3654 return;
3657 if (total_data < 42) {
3658 DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n",
3659 total_data));
3660 reply_nterror(
3661 req,
3662 NT_STATUS_INVALID_PARAMETER);
3663 return;
3666 /* unknown_1 24 NULL bytes in pdata*/
3668 /* the soft quotas 8 bytes (uint64_t)*/
3669 quotas.softlim = (uint64_t)IVAL(pdata,24);
3670 #ifdef LARGE_SMB_OFF_T
3671 quotas.softlim |= (((uint64_t)IVAL(pdata,28)) << 32);
3672 #else /* LARGE_SMB_OFF_T */
3673 if ((IVAL(pdata,28) != 0)&&
3674 ((quotas.softlim != 0xFFFFFFFF)||
3675 (IVAL(pdata,28)!=0xFFFFFFFF))) {
3676 /* more than 32 bits? */
3677 reply_nterror(
3678 req,
3679 NT_STATUS_INVALID_PARAMETER);
3680 return;
3682 #endif /* LARGE_SMB_OFF_T */
3684 /* the hard quotas 8 bytes (uint64_t)*/
3685 quotas.hardlim = (uint64_t)IVAL(pdata,32);
3686 #ifdef LARGE_SMB_OFF_T
3687 quotas.hardlim |= (((uint64_t)IVAL(pdata,36)) << 32);
3688 #else /* LARGE_SMB_OFF_T */
3689 if ((IVAL(pdata,36) != 0)&&
3690 ((quotas.hardlim != 0xFFFFFFFF)||
3691 (IVAL(pdata,36)!=0xFFFFFFFF))) {
3692 /* more than 32 bits? */
3693 reply_nterror(
3694 req,
3695 NT_STATUS_INVALID_PARAMETER);
3696 return;
3698 #endif /* LARGE_SMB_OFF_T */
3700 /* quota_flags 2 bytes **/
3701 quotas.qflags = SVAL(pdata,40);
3703 /* unknown_2 6 NULL bytes follow*/
3705 /* now set the quotas */
3706 if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
3707 DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3708 reply_nterror(req, map_nt_error_from_unix(errno));
3709 return;
3712 break;
3714 default:
3715 DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
3716 info_level));
3717 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
3718 return;
3719 break;
3723 * sending this reply works fine,
3724 * but I'm not sure it's the same
3725 * like windows do...
3726 * --metze
3728 reply_outbuf(req, 10, 0);
3731 #if defined(HAVE_POSIX_ACLS)
3732 /****************************************************************************
3733 Utility function to count the number of entries in a POSIX acl.
3734 ****************************************************************************/
3736 static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
3738 unsigned int ace_count = 0;
3739 int entry_id = SMB_ACL_FIRST_ENTRY;
3740 SMB_ACL_ENTRY_T entry;
3742 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
3743 /* get_next... */
3744 if (entry_id == SMB_ACL_FIRST_ENTRY) {
3745 entry_id = SMB_ACL_NEXT_ENTRY;
3747 ace_count++;
3749 return ace_count;
3752 /****************************************************************************
3753 Utility function to marshall a POSIX acl into wire format.
3754 ****************************************************************************/
3756 static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
3758 int entry_id = SMB_ACL_FIRST_ENTRY;
3759 SMB_ACL_ENTRY_T entry;
3761 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
3762 SMB_ACL_TAG_T tagtype;
3763 SMB_ACL_PERMSET_T permset;
3764 unsigned char perms = 0;
3765 unsigned int own_grp;
3767 /* get_next... */
3768 if (entry_id == SMB_ACL_FIRST_ENTRY) {
3769 entry_id = SMB_ACL_NEXT_ENTRY;
3772 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3773 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
3774 return False;
3777 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3778 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
3779 return False;
3782 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
3783 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
3784 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
3786 SCVAL(pdata,1,perms);
3788 switch (tagtype) {
3789 case SMB_ACL_USER_OBJ:
3790 SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
3791 own_grp = (unsigned int)pst->st_ex_uid;
3792 SIVAL(pdata,2,own_grp);
3793 SIVAL(pdata,6,0);
3794 break;
3795 case SMB_ACL_USER:
3797 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3798 if (!puid) {
3799 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
3800 return False;
3802 own_grp = (unsigned int)*puid;
3803 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
3804 SCVAL(pdata,0,SMB_POSIX_ACL_USER);
3805 SIVAL(pdata,2,own_grp);
3806 SIVAL(pdata,6,0);
3807 break;
3809 case SMB_ACL_GROUP_OBJ:
3810 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
3811 own_grp = (unsigned int)pst->st_ex_gid;
3812 SIVAL(pdata,2,own_grp);
3813 SIVAL(pdata,6,0);
3814 break;
3815 case SMB_ACL_GROUP:
3817 gid_t *pgid= (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3818 if (!pgid) {
3819 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
3820 return False;
3822 own_grp = (unsigned int)*pgid;
3823 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
3824 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
3825 SIVAL(pdata,2,own_grp);
3826 SIVAL(pdata,6,0);
3827 break;
3829 case SMB_ACL_MASK:
3830 SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
3831 SIVAL(pdata,2,0xFFFFFFFF);
3832 SIVAL(pdata,6,0xFFFFFFFF);
3833 break;
3834 case SMB_ACL_OTHER:
3835 SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
3836 SIVAL(pdata,2,0xFFFFFFFF);
3837 SIVAL(pdata,6,0xFFFFFFFF);
3838 break;
3839 default:
3840 DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
3841 return False;
3843 pdata += SMB_POSIX_ACL_ENTRY_SIZE;
3846 return True;
3848 #endif
3850 /****************************************************************************
3851 Store the FILE_UNIX_BASIC info.
3852 ****************************************************************************/
3854 static char *store_file_unix_basic(connection_struct *conn,
3855 char *pdata,
3856 files_struct *fsp,
3857 const SMB_STRUCT_STAT *psbuf)
3859 DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
3860 DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode));
3862 SOFF_T(pdata,0,get_file_size_stat(psbuf)); /* File size 64 Bit */
3863 pdata += 8;
3865 SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
3866 pdata += 8;
3868 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, psbuf->st_ex_ctime); /* Change Time 64 Bit */
3869 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, psbuf->st_ex_atime); /* Last access time 64 Bit */
3870 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, psbuf->st_ex_mtime); /* Last modification time 64 Bit */
3871 pdata += 24;
3873 SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */
3874 SIVAL(pdata,4,0);
3875 pdata += 8;
3877 SIVAL(pdata,0,psbuf->st_ex_gid); /* group id of owner */
3878 SIVAL(pdata,4,0);
3879 pdata += 8;
3881 SIVAL(pdata,0,unix_filetype(psbuf->st_ex_mode));
3882 pdata += 4;
3884 SIVAL(pdata,0,unix_dev_major(psbuf->st_ex_rdev)); /* Major device number if type is device */
3885 SIVAL(pdata,4,0);
3886 pdata += 8;
3888 SIVAL(pdata,0,unix_dev_minor(psbuf->st_ex_rdev)); /* Minor device number if type is device */
3889 SIVAL(pdata,4,0);
3890 pdata += 8;
3892 SINO_T_VAL(pdata,0,(SMB_INO_T)psbuf->st_ex_ino); /* inode number */
3893 pdata += 8;
3895 SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode)); /* Standard UNIX file permissions */
3896 SIVAL(pdata,4,0);
3897 pdata += 8;
3899 SIVAL(pdata,0,psbuf->st_ex_nlink); /* number of hard links */
3900 SIVAL(pdata,4,0);
3901 pdata += 8;
3903 return pdata;
3906 /* Forward and reverse mappings from the UNIX_INFO2 file flags field and
3907 * the chflags(2) (or equivalent) flags.
3909 * XXX: this really should be behind the VFS interface. To do this, we would
3910 * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field.
3911 * Each VFS module could then implement its own mapping as appropriate for the
3912 * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS.
3914 static const struct {unsigned stat_fflag; unsigned smb_fflag;}
3915 info2_flags_map[] =
3917 #ifdef UF_NODUMP
3918 { UF_NODUMP, EXT_DO_NOT_BACKUP },
3919 #endif
3921 #ifdef UF_IMMUTABLE
3922 { UF_IMMUTABLE, EXT_IMMUTABLE },
3923 #endif
3925 #ifdef UF_APPEND
3926 { UF_APPEND, EXT_OPEN_APPEND_ONLY },
3927 #endif
3929 #ifdef UF_HIDDEN
3930 { UF_HIDDEN, EXT_HIDDEN },
3931 #endif
3933 /* Do not remove. We need to guarantee that this array has at least one
3934 * entry to build on HP-UX.
3936 { 0, 0 }
3940 static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
3941 uint32 *smb_fflags, uint32 *smb_fmask)
3943 int i;
3945 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3946 *smb_fmask |= info2_flags_map[i].smb_fflag;
3947 if (psbuf->st_ex_flags & info2_flags_map[i].stat_fflag) {
3948 *smb_fflags |= info2_flags_map[i].smb_fflag;
3953 static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
3954 const uint32 smb_fflags,
3955 const uint32 smb_fmask,
3956 int *stat_fflags)
3958 uint32 max_fmask = 0;
3959 int i;
3961 *stat_fflags = psbuf->st_ex_flags;
3963 /* For each flags requested in smb_fmask, check the state of the
3964 * corresponding flag in smb_fflags and set or clear the matching
3965 * stat flag.
3968 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3969 max_fmask |= info2_flags_map[i].smb_fflag;
3970 if (smb_fmask & info2_flags_map[i].smb_fflag) {
3971 if (smb_fflags & info2_flags_map[i].smb_fflag) {
3972 *stat_fflags |= info2_flags_map[i].stat_fflag;
3973 } else {
3974 *stat_fflags &= ~info2_flags_map[i].stat_fflag;
3979 /* If smb_fmask is asking to set any bits that are not supported by
3980 * our flag mappings, we should fail.
3982 if ((smb_fmask & max_fmask) != smb_fmask) {
3983 return False;
3986 return True;
3990 /* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition
3991 * of file flags and birth (create) time.
3993 static char *store_file_unix_basic_info2(connection_struct *conn,
3994 char *pdata,
3995 files_struct *fsp,
3996 const SMB_STRUCT_STAT *psbuf)
3998 uint32 file_flags = 0;
3999 uint32 flags_mask = 0;
4001 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
4003 /* Create (birth) time 64 bit */
4004 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, psbuf->st_ex_btime);
4005 pdata += 8;
4007 map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
4008 SIVAL(pdata, 0, file_flags); /* flags */
4009 SIVAL(pdata, 4, flags_mask); /* mask */
4010 pdata += 8;
4012 return pdata;
4015 static NTSTATUS marshall_stream_info(unsigned int num_streams,
4016 const struct stream_struct *streams,
4017 char *data,
4018 unsigned int max_data_bytes,
4019 unsigned int *data_size)
4021 unsigned int i;
4022 unsigned int ofs = 0;
4024 for (i = 0; i < num_streams && ofs <= max_data_bytes; i++) {
4025 unsigned int next_offset;
4026 size_t namelen;
4027 smb_ucs2_t *namebuf;
4029 if (!push_ucs2_talloc(talloc_tos(), &namebuf,
4030 streams[i].name, &namelen) ||
4031 namelen <= 2)
4033 return NT_STATUS_INVALID_PARAMETER;
4037 * name_buf is now null-terminated, we need to marshall as not
4038 * terminated
4041 namelen -= 2;
4043 SIVAL(data, ofs+4, namelen);
4044 SOFF_T(data, ofs+8, streams[i].size);
4045 SOFF_T(data, ofs+16, streams[i].alloc_size);
4046 memcpy(data+ofs+24, namebuf, namelen);
4047 TALLOC_FREE(namebuf);
4049 next_offset = ofs + 24 + namelen;
4051 if (i == num_streams-1) {
4052 SIVAL(data, ofs, 0);
4054 else {
4055 unsigned int align = ndr_align_size(next_offset, 8);
4057 memset(data+next_offset, 0, align);
4058 next_offset += align;
4060 SIVAL(data, ofs, next_offset - ofs);
4061 ofs = next_offset;
4064 ofs = next_offset;
4067 *data_size = ofs;
4069 return NT_STATUS_OK;
4072 /****************************************************************************
4073 Reply to a TRANSACT2_QFILEINFO on a PIPE !
4074 ****************************************************************************/
4076 static void call_trans2qpipeinfo(connection_struct *conn,
4077 struct smb_request *req,
4078 unsigned int tran_call,
4079 char **pparams, int total_params,
4080 char **ppdata, int total_data,
4081 unsigned int max_data_bytes)
4083 char *params = *pparams;
4084 char *pdata = *ppdata;
4085 unsigned int data_size = 0;
4086 unsigned int param_size = 2;
4087 uint16 info_level;
4088 files_struct *fsp;
4090 if (!params) {
4091 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4092 return;
4095 if (total_params < 4) {
4096 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4097 return;
4100 fsp = file_fsp(req, SVAL(params,0));
4101 if (!fsp_is_np(fsp)) {
4102 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4103 return;
4106 info_level = SVAL(params,2);
4108 *pparams = (char *)SMB_REALLOC(*pparams,2);
4109 if (*pparams == NULL) {
4110 reply_nterror(req, NT_STATUS_NO_MEMORY);
4111 return;
4113 params = *pparams;
4114 SSVAL(params,0,0);
4115 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
4116 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
4117 if (*ppdata == NULL ) {
4118 reply_nterror(req, NT_STATUS_NO_MEMORY);
4119 return;
4121 pdata = *ppdata;
4123 switch (info_level) {
4124 case SMB_FILE_STANDARD_INFORMATION:
4125 memset(pdata,0,24);
4126 SOFF_T(pdata,0,4096LL);
4127 SIVAL(pdata,16,1);
4128 SIVAL(pdata,20,1);
4129 data_size = 24;
4130 break;
4132 default:
4133 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4134 return;
4137 send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
4138 max_data_bytes);
4140 return;
4143 NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
4144 TALLOC_CTX *mem_ctx,
4145 uint16_t info_level,
4146 files_struct *fsp,
4147 struct smb_filename *smb_fname,
4148 bool delete_pending,
4149 struct timespec write_time_ts,
4150 bool ms_dfs_link,
4151 struct ea_list *ea_list,
4152 int lock_data_count,
4153 char *lock_data,
4154 uint16_t flags2,
4155 unsigned int max_data_bytes,
4156 char **ppdata,
4157 unsigned int *pdata_size)
4159 char *pdata = *ppdata;
4160 char *dstart, *dend;
4161 unsigned int data_size;
4162 struct timespec create_time_ts, mtime_ts, atime_ts, ctime_ts;
4163 time_t create_time, mtime, atime, c_time;
4164 SMB_STRUCT_STAT *psbuf = &smb_fname->st;
4165 char *p;
4166 char *base_name;
4167 char *dos_fname;
4168 int mode;
4169 int nlink;
4170 NTSTATUS status;
4171 uint64_t file_size = 0;
4172 uint64_t pos = 0;
4173 uint64_t allocation_size = 0;
4174 uint64_t file_index = 0;
4175 uint32_t access_mask = 0;
4177 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
4178 return NT_STATUS_INVALID_LEVEL;
4181 DEBUG(5,("smbd_do_qfilepathinfo: %s (fnum = %d) level=%d max_data=%u\n",
4182 smb_fname_str_dbg(smb_fname), fsp ? fsp->fnum : -1,
4183 info_level, max_data_bytes));
4185 if (ms_dfs_link) {
4186 mode = dos_mode_msdfs(conn, smb_fname);
4187 } else {
4188 mode = dos_mode(conn, smb_fname);
4190 if (!mode)
4191 mode = FILE_ATTRIBUTE_NORMAL;
4193 nlink = psbuf->st_ex_nlink;
4195 if (nlink && (mode&aDIR)) {
4196 nlink = 1;
4199 if ((nlink > 0) && delete_pending) {
4200 nlink -= 1;
4203 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
4204 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
4205 if (*ppdata == NULL) {
4206 return NT_STATUS_NO_MEMORY;
4208 pdata = *ppdata;
4209 dstart = pdata;
4210 dend = dstart + data_size - 1;
4212 if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) {
4213 update_stat_ex_mtime(psbuf, write_time_ts);
4216 create_time_ts = get_create_timespec(conn, fsp, smb_fname);
4217 mtime_ts = psbuf->st_ex_mtime;
4218 atime_ts = psbuf->st_ex_atime;
4219 ctime_ts = get_change_timespec(conn, fsp, smb_fname);
4221 if (lp_dos_filetime_resolution(SNUM(conn))) {
4222 dos_filetime_timespec(&create_time_ts);
4223 dos_filetime_timespec(&mtime_ts);
4224 dos_filetime_timespec(&atime_ts);
4225 dos_filetime_timespec(&ctime_ts);
4228 create_time = convert_timespec_to_time_t(create_time_ts);
4229 mtime = convert_timespec_to_time_t(mtime_ts);
4230 atime = convert_timespec_to_time_t(atime_ts);
4231 c_time = convert_timespec_to_time_t(ctime_ts);
4233 p = strrchr_m(smb_fname->base_name,'/');
4234 if (!p)
4235 base_name = smb_fname->base_name;
4236 else
4237 base_name = p+1;
4239 /* NT expects the name to be in an exact form of the *full*
4240 filename. See the trans2 torture test */
4241 if (ISDOT(base_name)) {
4242 dos_fname = talloc_strdup(mem_ctx, "\\");
4243 if (!dos_fname) {
4244 return NT_STATUS_NO_MEMORY;
4246 } else {
4247 dos_fname = talloc_asprintf(mem_ctx,
4248 "\\%s",
4249 smb_fname->base_name);
4250 if (!dos_fname) {
4251 return NT_STATUS_NO_MEMORY;
4253 if (is_ntfs_stream_smb_fname(smb_fname)) {
4254 dos_fname = talloc_asprintf(dos_fname, "%s",
4255 smb_fname->stream_name);
4256 if (!dos_fname) {
4257 return NT_STATUS_NO_MEMORY;
4261 string_replace(dos_fname, '/', '\\');
4264 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, psbuf);
4266 if (!fsp) {
4267 /* Do we have this path open ? */
4268 files_struct *fsp1;
4269 struct file_id fileid = vfs_file_id_from_sbuf(conn, psbuf);
4270 fsp1 = file_find_di_first(fileid);
4271 if (fsp1 && fsp1->initial_allocation_size) {
4272 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, psbuf);
4276 if (!(mode & aDIR)) {
4277 file_size = get_file_size_stat(psbuf);
4280 if (fsp) {
4281 pos = fsp->fh->position_information;
4284 if (fsp) {
4285 access_mask = fsp->access_mask;
4286 } else {
4287 /* GENERIC_EXECUTE mapping from Windows */
4288 access_mask = 0x12019F;
4291 /* This should be an index number - looks like
4292 dev/ino to me :-)
4294 I think this causes us to fail the IFSKIT
4295 BasicFileInformationTest. -tpot */
4296 file_index = ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */
4297 file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */
4299 switch (info_level) {
4300 case SMB_INFO_STANDARD:
4301 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
4302 data_size = 22;
4303 srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
4304 srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
4305 srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
4306 SIVAL(pdata,l1_cbFile,(uint32)file_size);
4307 SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
4308 SSVAL(pdata,l1_attrFile,mode);
4309 break;
4311 case SMB_INFO_QUERY_EA_SIZE:
4313 unsigned int ea_size =
4314 estimate_ea_size(conn, fsp,
4315 smb_fname->base_name);
4316 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
4317 data_size = 26;
4318 srv_put_dos_date2(pdata,0,create_time);
4319 srv_put_dos_date2(pdata,4,atime);
4320 srv_put_dos_date2(pdata,8,mtime); /* write time */
4321 SIVAL(pdata,12,(uint32)file_size);
4322 SIVAL(pdata,16,(uint32)allocation_size);
4323 SSVAL(pdata,20,mode);
4324 SIVAL(pdata,22,ea_size);
4325 break;
4328 case SMB_INFO_IS_NAME_VALID:
4329 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
4330 if (fsp) {
4331 /* os/2 needs this ? really ?*/
4332 return NT_STATUS_DOS(ERRDOS, ERRbadfunc);
4334 /* This is only reached for qpathinfo */
4335 data_size = 0;
4336 break;
4338 case SMB_INFO_QUERY_EAS_FROM_LIST:
4340 size_t total_ea_len = 0;
4341 struct ea_list *ea_file_list = NULL;
4343 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
4345 ea_file_list =
4346 get_ea_list_from_file(mem_ctx, conn, fsp,
4347 smb_fname->base_name,
4348 &total_ea_len);
4349 ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
4351 if (!ea_list || (total_ea_len > data_size)) {
4352 data_size = 4;
4353 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
4354 break;
4357 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
4358 break;
4361 case SMB_INFO_QUERY_ALL_EAS:
4363 /* We have data_size bytes to put EA's into. */
4364 size_t total_ea_len = 0;
4366 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
4368 ea_list = get_ea_list_from_file(mem_ctx, conn, fsp,
4369 smb_fname->base_name,
4370 &total_ea_len);
4371 if (!ea_list || (total_ea_len > data_size)) {
4372 data_size = 4;
4373 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
4374 break;
4377 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
4378 break;
4381 case 0xFF0F:/*SMB2_INFO_QUERY_ALL_EAS*/
4383 /* This is FileFullEaInformation - 0xF which maps to
4384 * 1015 (decimal) in smbd_do_setfilepathinfo. */
4386 /* We have data_size bytes to put EA's into. */
4387 size_t total_ea_len = 0;
4388 struct ea_list *ea_file_list = NULL;
4390 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n"));
4392 /*TODO: add filtering and index handling */
4394 ea_file_list =
4395 get_ea_list_from_file(mem_ctx, conn, fsp,
4396 smb_fname->base_name,
4397 &total_ea_len);
4398 if (!ea_file_list) {
4399 return NT_STATUS_NO_EAS_ON_FILE;
4402 status = fill_ea_chained_buffer(mem_ctx,
4403 pdata,
4404 data_size,
4405 &data_size,
4406 conn, ea_file_list);
4407 if (!NT_STATUS_IS_OK(status)) {
4408 return status;
4410 break;
4413 case SMB_FILE_BASIC_INFORMATION:
4414 case SMB_QUERY_FILE_BASIC_INFO:
4416 if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
4417 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
4418 data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
4419 } else {
4420 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
4421 data_size = 40;
4422 SIVAL(pdata,36,0);
4424 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
4425 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
4426 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
4427 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
4428 SIVAL(pdata,32,mode);
4430 DEBUG(5,("SMB_QFBI - "));
4431 DEBUG(5,("create: %s ", ctime(&create_time)));
4432 DEBUG(5,("access: %s ", ctime(&atime)));
4433 DEBUG(5,("write: %s ", ctime(&mtime)));
4434 DEBUG(5,("change: %s ", ctime(&c_time)));
4435 DEBUG(5,("mode: %x\n", mode));
4436 break;
4438 case SMB_FILE_STANDARD_INFORMATION:
4439 case SMB_QUERY_FILE_STANDARD_INFO:
4441 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
4442 data_size = 24;
4443 SOFF_T(pdata,0,allocation_size);
4444 SOFF_T(pdata,8,file_size);
4445 SIVAL(pdata,16,nlink);
4446 SCVAL(pdata,20,delete_pending?1:0);
4447 SCVAL(pdata,21,(mode&aDIR)?1:0);
4448 SSVAL(pdata,22,0); /* Padding. */
4449 break;
4451 case SMB_FILE_EA_INFORMATION:
4452 case SMB_QUERY_FILE_EA_INFO:
4454 unsigned int ea_size =
4455 estimate_ea_size(conn, fsp, smb_fname->base_name);
4456 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
4457 data_size = 4;
4458 SIVAL(pdata,0,ea_size);
4459 break;
4462 /* Get the 8.3 name - used if NT SMB was negotiated. */
4463 case SMB_QUERY_FILE_ALT_NAME_INFO:
4464 case SMB_FILE_ALTERNATE_NAME_INFORMATION:
4466 int len;
4467 char mangled_name[13];
4468 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
4469 if (!name_to_8_3(base_name,mangled_name,
4470 True,conn->params)) {
4471 return NT_STATUS_NO_MEMORY;
4473 len = srvstr_push(dstart, flags2,
4474 pdata+4, mangled_name,
4475 PTR_DIFF(dend, pdata+4),
4476 STR_UNICODE);
4477 data_size = 4 + len;
4478 SIVAL(pdata,0,len);
4479 break;
4482 case SMB_QUERY_FILE_NAME_INFO:
4484 int len;
4486 this must be *exactly* right for ACLs on mapped drives to work
4488 len = srvstr_push(dstart, flags2,
4489 pdata+4, dos_fname,
4490 PTR_DIFF(dend, pdata+4),
4491 STR_UNICODE);
4492 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
4493 data_size = 4 + len;
4494 SIVAL(pdata,0,len);
4495 break;
4498 case SMB_FILE_ALLOCATION_INFORMATION:
4499 case SMB_QUERY_FILE_ALLOCATION_INFO:
4500 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
4501 data_size = 8;
4502 SOFF_T(pdata,0,allocation_size);
4503 break;
4505 case SMB_FILE_END_OF_FILE_INFORMATION:
4506 case SMB_QUERY_FILE_END_OF_FILEINFO:
4507 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
4508 data_size = 8;
4509 SOFF_T(pdata,0,file_size);
4510 break;
4512 case SMB_QUERY_FILE_ALL_INFO:
4513 case SMB_FILE_ALL_INFORMATION:
4515 int len;
4516 unsigned int ea_size =
4517 estimate_ea_size(conn, fsp, smb_fname->base_name);
4518 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
4519 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
4520 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
4521 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
4522 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
4523 SIVAL(pdata,32,mode);
4524 SIVAL(pdata,36,0); /* padding. */
4525 pdata += 40;
4526 SOFF_T(pdata,0,allocation_size);
4527 SOFF_T(pdata,8,file_size);
4528 SIVAL(pdata,16,nlink);
4529 SCVAL(pdata,20,delete_pending);
4530 SCVAL(pdata,21,(mode&aDIR)?1:0);
4531 SSVAL(pdata,22,0);
4532 pdata += 24;
4533 SIVAL(pdata,0,ea_size);
4534 pdata += 4; /* EA info */
4535 len = srvstr_push(dstart, flags2,
4536 pdata+4, dos_fname,
4537 PTR_DIFF(dend, pdata+4),
4538 STR_UNICODE);
4539 SIVAL(pdata,0,len);
4540 pdata += 4 + len;
4541 data_size = PTR_DIFF(pdata,(*ppdata));
4542 break;
4545 case 0xFF12:/*SMB2_FILE_ALL_INFORMATION*/
4547 int len;
4548 unsigned int ea_size =
4549 estimate_ea_size(conn, fsp, smb_fname->base_name);
4550 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
4551 put_long_date_timespec(conn->ts_res,pdata+0x00,create_time_ts);
4552 put_long_date_timespec(conn->ts_res,pdata+0x08,atime_ts);
4553 put_long_date_timespec(conn->ts_res,pdata+0x10,mtime_ts); /* write time */
4554 put_long_date_timespec(conn->ts_res,pdata+0x18,ctime_ts); /* change time */
4555 SIVAL(pdata, 0x20, mode);
4556 SIVAL(pdata, 0x24, 0); /* padding. */
4557 SBVAL(pdata, 0x28, allocation_size);
4558 SBVAL(pdata, 0x30, file_size);
4559 SIVAL(pdata, 0x38, nlink);
4560 SCVAL(pdata, 0x3C, delete_pending);
4561 SCVAL(pdata, 0x3D, (mode&aDIR)?1:0);
4562 SSVAL(pdata, 0x3E, 0); /* padding */
4563 SBVAL(pdata, 0x40, file_index);
4564 SIVAL(pdata, 0x48, ea_size);
4565 SIVAL(pdata, 0x4C, access_mask);
4566 SBVAL(pdata, 0x50, pos);
4567 SIVAL(pdata, 0x58, mode); /*TODO: mode != mode fix this!!! */
4568 SIVAL(pdata, 0x5C, 0); /* No alignment needed. */
4570 pdata += 0x60;
4572 len = srvstr_push(dstart, flags2,
4573 pdata+4, dos_fname,
4574 PTR_DIFF(dend, pdata+4),
4575 STR_UNICODE);
4576 SIVAL(pdata,0,len);
4577 pdata += 4 + len;
4578 data_size = PTR_DIFF(pdata,(*ppdata));
4579 break;
4581 case SMB_FILE_INTERNAL_INFORMATION:
4583 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
4584 SBVAL(pdata, 0, file_index);
4585 data_size = 8;
4586 break;
4588 case SMB_FILE_ACCESS_INFORMATION:
4589 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
4590 SIVAL(pdata, 0, access_mask);
4591 data_size = 4;
4592 break;
4594 case SMB_FILE_NAME_INFORMATION:
4595 /* Pathname with leading '\'. */
4597 size_t byte_len;
4598 byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
4599 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
4600 SIVAL(pdata,0,byte_len);
4601 data_size = 4 + byte_len;
4602 break;
4605 case SMB_FILE_DISPOSITION_INFORMATION:
4606 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
4607 data_size = 1;
4608 SCVAL(pdata,0,delete_pending);
4609 break;
4611 case SMB_FILE_POSITION_INFORMATION:
4612 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
4613 data_size = 8;
4614 SOFF_T(pdata,0,pos);
4615 break;
4617 case SMB_FILE_MODE_INFORMATION:
4618 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
4619 SIVAL(pdata,0,mode);
4620 data_size = 4;
4621 break;
4623 case SMB_FILE_ALIGNMENT_INFORMATION:
4624 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
4625 SIVAL(pdata,0,0); /* No alignment needed. */
4626 data_size = 4;
4627 break;
4630 * NT4 server just returns "invalid query" to this - if we try
4631 * to answer it then NTws gets a BSOD! (tridge). W2K seems to
4632 * want this. JRA.
4634 /* The first statement above is false - verified using Thursby
4635 * client against NT4 -- gcolley.
4637 case SMB_QUERY_FILE_STREAM_INFO:
4638 case SMB_FILE_STREAM_INFORMATION: {
4639 unsigned int num_streams;
4640 struct stream_struct *streams;
4642 DEBUG(10,("smbd_do_qfilepathinfo: "
4643 "SMB_FILE_STREAM_INFORMATION\n"));
4645 if (is_ntfs_stream_smb_fname(smb_fname)) {
4646 return NT_STATUS_INVALID_PARAMETER;
4649 status = SMB_VFS_STREAMINFO(
4650 conn, fsp, smb_fname->base_name, talloc_tos(),
4651 &num_streams, &streams);
4653 if (!NT_STATUS_IS_OK(status)) {
4654 DEBUG(10, ("could not get stream info: %s\n",
4655 nt_errstr(status)));
4656 return status;
4659 status = marshall_stream_info(num_streams, streams,
4660 pdata, max_data_bytes,
4661 &data_size);
4663 if (!NT_STATUS_IS_OK(status)) {
4664 DEBUG(10, ("marshall_stream_info failed: %s\n",
4665 nt_errstr(status)));
4666 return status;
4669 TALLOC_FREE(streams);
4671 break;
4673 case SMB_QUERY_COMPRESSION_INFO:
4674 case SMB_FILE_COMPRESSION_INFORMATION:
4675 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
4676 SOFF_T(pdata,0,file_size);
4677 SIVAL(pdata,8,0); /* ??? */
4678 SIVAL(pdata,12,0); /* ??? */
4679 data_size = 16;
4680 break;
4682 case SMB_FILE_NETWORK_OPEN_INFORMATION:
4683 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
4684 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
4685 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
4686 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
4687 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
4688 SOFF_T(pdata,32,allocation_size);
4689 SOFF_T(pdata,40,file_size);
4690 SIVAL(pdata,48,mode);
4691 SIVAL(pdata,52,0); /* ??? */
4692 data_size = 56;
4693 break;
4695 case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
4696 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
4697 SIVAL(pdata,0,mode);
4698 SIVAL(pdata,4,0);
4699 data_size = 8;
4700 break;
4703 * CIFS UNIX Extensions.
4706 case SMB_QUERY_FILE_UNIX_BASIC:
4708 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
4709 data_size = PTR_DIFF(pdata,(*ppdata));
4712 int i;
4713 DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC "));
4715 for (i=0; i<100; i++)
4716 DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
4717 DEBUG(4,("\n"));
4720 break;
4722 case SMB_QUERY_FILE_UNIX_INFO2:
4724 pdata = store_file_unix_basic_info2(conn, pdata, fsp, psbuf);
4725 data_size = PTR_DIFF(pdata,(*ppdata));
4728 int i;
4729 DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));
4731 for (i=0; i<100; i++)
4732 DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
4733 DEBUG(4,("\n"));
4736 break;
4738 case SMB_QUERY_FILE_UNIX_LINK:
4740 int len;
4741 char *buffer = TALLOC_ARRAY(mem_ctx, char, PATH_MAX+1);
4743 if (!buffer) {
4744 return NT_STATUS_NO_MEMORY;
4747 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n"));
4748 #ifdef S_ISLNK
4749 if(!S_ISLNK(psbuf->st_ex_mode)) {
4750 return NT_STATUS_DOS(ERRSRV, ERRbadlink);
4752 #else
4753 return NT_STATUS_DOS(ERRDOS, ERRbadlink);
4754 #endif
4755 len = SMB_VFS_READLINK(conn,
4756 smb_fname->base_name,
4757 buffer, PATH_MAX);
4758 if (len == -1) {
4759 return map_nt_error_from_unix(errno);
4761 buffer[len] = 0;
4762 len = srvstr_push(dstart, flags2,
4763 pdata, buffer,
4764 PTR_DIFF(dend, pdata),
4765 STR_TERMINATE);
4766 pdata += len;
4767 data_size = PTR_DIFF(pdata,(*ppdata));
4769 break;
4772 #if defined(HAVE_POSIX_ACLS)
4773 case SMB_QUERY_POSIX_ACL:
4775 SMB_ACL_T file_acl = NULL;
4776 SMB_ACL_T def_acl = NULL;
4777 uint16 num_file_acls = 0;
4778 uint16 num_def_acls = 0;
4780 if (fsp && !fsp->is_directory && (fsp->fh->fd != -1)) {
4781 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
4782 } else {
4783 file_acl =
4784 SMB_VFS_SYS_ACL_GET_FILE(conn,
4785 smb_fname->base_name,
4786 SMB_ACL_TYPE_ACCESS);
4789 if (file_acl == NULL && no_acl_syscall_error(errno)) {
4790 DEBUG(5,("smbd_do_qfilepathinfo: ACLs "
4791 "not implemented on "
4792 "filesystem containing %s\n",
4793 smb_fname->base_name));
4794 return NT_STATUS_NOT_IMPLEMENTED;
4797 if (S_ISDIR(psbuf->st_ex_mode)) {
4798 if (fsp && fsp->is_directory) {
4799 def_acl =
4800 SMB_VFS_SYS_ACL_GET_FILE(
4801 conn,
4802 fsp->fsp_name->base_name,
4803 SMB_ACL_TYPE_DEFAULT);
4804 } else {
4805 def_acl =
4806 SMB_VFS_SYS_ACL_GET_FILE(
4807 conn,
4808 smb_fname->base_name,
4809 SMB_ACL_TYPE_DEFAULT);
4811 def_acl = free_empty_sys_acl(conn, def_acl);
4814 num_file_acls = count_acl_entries(conn, file_acl);
4815 num_def_acls = count_acl_entries(conn, def_acl);
4817 if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) {
4818 DEBUG(5,("smbd_do_qfilepathinfo: data_size too small (%u) need %u\n",
4819 data_size,
4820 (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
4821 SMB_POSIX_ACL_HEADER_SIZE) ));
4822 if (file_acl) {
4823 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4825 if (def_acl) {
4826 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4828 return NT_STATUS_BUFFER_TOO_SMALL;
4831 SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
4832 SSVAL(pdata,2,num_file_acls);
4833 SSVAL(pdata,4,num_def_acls);
4834 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, psbuf, file_acl)) {
4835 if (file_acl) {
4836 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4838 if (def_acl) {
4839 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4841 return NT_STATUS_INTERNAL_ERROR;
4843 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), psbuf, def_acl)) {
4844 if (file_acl) {
4845 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4847 if (def_acl) {
4848 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4850 return NT_STATUS_INTERNAL_ERROR;
4853 if (file_acl) {
4854 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4856 if (def_acl) {
4857 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4859 data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
4860 break;
4862 #endif
4865 case SMB_QUERY_POSIX_LOCK:
4867 uint64_t count;
4868 uint64_t offset;
4869 uint32 lock_pid;
4870 enum brl_type lock_type;
4872 /* We need an open file with a real fd for this. */
4873 if (!fsp || fsp->is_directory || fsp->fh->fd == -1) {
4874 return NT_STATUS_INVALID_LEVEL;
4877 if (lock_data_count != POSIX_LOCK_DATA_SIZE) {
4878 return NT_STATUS_INVALID_PARAMETER;
4881 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
4882 case POSIX_LOCK_TYPE_READ:
4883 lock_type = READ_LOCK;
4884 break;
4885 case POSIX_LOCK_TYPE_WRITE:
4886 lock_type = WRITE_LOCK;
4887 break;
4888 case POSIX_LOCK_TYPE_UNLOCK:
4889 default:
4890 /* There's no point in asking for an unlock... */
4891 return NT_STATUS_INVALID_PARAMETER;
4894 lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
4895 #if defined(HAVE_LONGLONG)
4896 offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
4897 ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
4898 count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
4899 ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
4900 #else /* HAVE_LONGLONG */
4901 offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET);
4902 count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
4903 #endif /* HAVE_LONGLONG */
4905 status = query_lock(fsp,
4906 &lock_pid,
4907 &count,
4908 &offset,
4909 &lock_type,
4910 POSIX_LOCK);
4912 if (ERROR_WAS_LOCK_DENIED(status)) {
4913 /* Here we need to report who has it locked... */
4914 data_size = POSIX_LOCK_DATA_SIZE;
4916 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
4917 SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
4918 SIVAL(pdata, POSIX_LOCK_PID_OFFSET, lock_pid);
4919 #if defined(HAVE_LONGLONG)
4920 SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF));
4921 SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF));
4922 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF));
4923 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF));
4924 #else /* HAVE_LONGLONG */
4925 SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
4926 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
4927 #endif /* HAVE_LONGLONG */
4929 } else if (NT_STATUS_IS_OK(status)) {
4930 /* For success we just return a copy of what we sent
4931 with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
4932 data_size = POSIX_LOCK_DATA_SIZE;
4933 memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
4934 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
4935 } else {
4936 return status;
4938 break;
4941 default:
4942 return NT_STATUS_INVALID_LEVEL;
4945 *pdata_size = data_size;
4946 return NT_STATUS_OK;
4949 /****************************************************************************
4950 Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
4951 file name or file id).
4952 ****************************************************************************/
4954 static void call_trans2qfilepathinfo(connection_struct *conn,
4955 struct smb_request *req,
4956 unsigned int tran_call,
4957 char **pparams, int total_params,
4958 char **ppdata, int total_data,
4959 unsigned int max_data_bytes)
4961 char *params = *pparams;
4962 char *pdata = *ppdata;
4963 uint16 info_level;
4964 unsigned int data_size = 0;
4965 unsigned int param_size = 2;
4966 struct smb_filename *smb_fname = NULL;
4967 bool delete_pending = False;
4968 struct timespec write_time_ts;
4969 files_struct *fsp = NULL;
4970 struct file_id fileid;
4971 struct ea_list *ea_list = NULL;
4972 int lock_data_count = 0;
4973 char *lock_data = NULL;
4974 bool ms_dfs_link = false;
4975 NTSTATUS status = NT_STATUS_OK;
4977 if (!params) {
4978 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4979 return;
4982 ZERO_STRUCT(write_time_ts);
4984 if (tran_call == TRANSACT2_QFILEINFO) {
4985 if (total_params < 4) {
4986 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4987 return;
4990 if (IS_IPC(conn)) {
4991 call_trans2qpipeinfo(conn, req, tran_call,
4992 pparams, total_params,
4993 ppdata, total_data,
4994 max_data_bytes);
4995 return;
4998 fsp = file_fsp(req, SVAL(params,0));
4999 info_level = SVAL(params,2);
5001 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
5003 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
5004 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5005 return;
5008 /* Initial check for valid fsp ptr. */
5009 if (!check_fsp_open(conn, req, fsp)) {
5010 return;
5013 status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
5014 &smb_fname);
5015 if (!NT_STATUS_IS_OK(status)) {
5016 reply_nterror(req, status);
5017 return;
5020 if(fsp->fake_file_handle) {
5022 * This is actually for the QUOTA_FAKE_FILE --metze
5025 /* We know this name is ok, it's already passed the checks. */
5027 } else if(fsp->is_directory || fsp->fh->fd == -1) {
5029 * This is actually a QFILEINFO on a directory
5030 * handle (returned from an NT SMB). NT5.0 seems
5031 * to do this call. JRA.
5034 if (INFO_LEVEL_IS_UNIX(info_level)) {
5035 /* Always do lstat for UNIX calls. */
5036 if (SMB_VFS_LSTAT(conn, smb_fname)) {
5037 DEBUG(3,("call_trans2qfilepathinfo: "
5038 "SMB_VFS_LSTAT of %s failed "
5039 "(%s)\n",
5040 smb_fname_str_dbg(smb_fname),
5041 strerror(errno)));
5042 reply_nterror(req,
5043 map_nt_error_from_unix(errno));
5044 return;
5046 } else if (SMB_VFS_STAT(conn, smb_fname)) {
5047 DEBUG(3,("call_trans2qfilepathinfo: "
5048 "SMB_VFS_STAT of %s failed (%s)\n",
5049 smb_fname_str_dbg(smb_fname),
5050 strerror(errno)));
5051 reply_nterror(req,
5052 map_nt_error_from_unix(errno));
5053 return;
5056 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5057 get_file_infos(fileid, &delete_pending, &write_time_ts);
5058 } else {
5060 * Original code - this is an open file.
5062 if (!check_fsp(conn, req, fsp)) {
5063 return;
5066 if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
5067 DEBUG(3, ("fstat of fnum %d failed (%s)\n",
5068 fsp->fnum, strerror(errno)));
5069 reply_nterror(req,
5070 map_nt_error_from_unix(errno));
5071 return;
5073 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5074 get_file_infos(fileid, &delete_pending, &write_time_ts);
5077 } else {
5078 char *fname = NULL;
5080 /* qpathinfo */
5081 if (total_params < 7) {
5082 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5083 return;
5086 info_level = SVAL(params,0);
5088 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
5090 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
5091 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5092 return;
5095 srvstr_get_path(req, params, req->flags2, &fname, &params[6],
5096 total_params - 6,
5097 STR_TERMINATE, &status);
5098 if (!NT_STATUS_IS_OK(status)) {
5099 reply_nterror(req, status);
5100 return;
5103 status = filename_convert(req,
5104 conn,
5105 req->flags2 & FLAGS2_DFS_PATHNAMES,
5106 fname,
5108 NULL,
5109 &smb_fname);
5110 if (!NT_STATUS_IS_OK(status)) {
5111 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5112 reply_botherror(req,
5113 NT_STATUS_PATH_NOT_COVERED,
5114 ERRSRV, ERRbadpath);
5115 return;
5117 reply_nterror(req, status);
5118 return;
5121 /* If this is a stream, check if there is a delete_pending. */
5122 if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
5123 && is_ntfs_stream_smb_fname(smb_fname)) {
5124 struct smb_filename *smb_fname_base = NULL;
5126 /* Create an smb_filename with stream_name == NULL. */
5127 status =
5128 create_synthetic_smb_fname(talloc_tos(),
5129 smb_fname->base_name,
5130 NULL, NULL,
5131 &smb_fname_base);
5132 if (!NT_STATUS_IS_OK(status)) {
5133 reply_nterror(req, status);
5134 return;
5137 if (INFO_LEVEL_IS_UNIX(info_level)) {
5138 /* Always do lstat for UNIX calls. */
5139 if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) {
5140 DEBUG(3,("call_trans2qfilepathinfo: "
5141 "SMB_VFS_LSTAT of %s failed "
5142 "(%s)\n",
5143 smb_fname_str_dbg(smb_fname_base),
5144 strerror(errno)));
5145 TALLOC_FREE(smb_fname_base);
5146 reply_nterror(req,
5147 map_nt_error_from_unix(errno));
5148 return;
5150 } else {
5151 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
5152 DEBUG(3,("call_trans2qfilepathinfo: "
5153 "fileinfo of %s failed "
5154 "(%s)\n",
5155 smb_fname_str_dbg(smb_fname_base),
5156 strerror(errno)));
5157 TALLOC_FREE(smb_fname_base);
5158 reply_nterror(req,
5159 map_nt_error_from_unix(errno));
5160 return;
5164 fileid = vfs_file_id_from_sbuf(conn,
5165 &smb_fname_base->st);
5166 TALLOC_FREE(smb_fname_base);
5167 get_file_infos(fileid, &delete_pending, NULL);
5168 if (delete_pending) {
5169 reply_nterror(req, NT_STATUS_DELETE_PENDING);
5170 return;
5174 if (INFO_LEVEL_IS_UNIX(info_level)) {
5175 /* Always do lstat for UNIX calls. */
5176 if (SMB_VFS_LSTAT(conn, smb_fname)) {
5177 DEBUG(3,("call_trans2qfilepathinfo: "
5178 "SMB_VFS_LSTAT of %s failed (%s)\n",
5179 smb_fname_str_dbg(smb_fname),
5180 strerror(errno)));
5181 reply_nterror(req,
5182 map_nt_error_from_unix(errno));
5183 return;
5186 } else if (!VALID_STAT(smb_fname->st) &&
5187 SMB_VFS_STAT(conn, smb_fname) &&
5188 (info_level != SMB_INFO_IS_NAME_VALID)) {
5189 ms_dfs_link = check_msdfs_link(conn,
5190 smb_fname->base_name,
5191 &smb_fname->st);
5193 if (!ms_dfs_link) {
5194 DEBUG(3,("call_trans2qfilepathinfo: "
5195 "SMB_VFS_STAT of %s failed (%s)\n",
5196 smb_fname_str_dbg(smb_fname),
5197 strerror(errno)));
5198 reply_nterror(req,
5199 map_nt_error_from_unix(errno));
5200 return;
5204 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5205 get_file_infos(fileid, &delete_pending, &write_time_ts);
5206 if (delete_pending) {
5207 reply_nterror(req, NT_STATUS_DELETE_PENDING);
5208 return;
5212 DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d "
5213 "total_data=%d\n", smb_fname_str_dbg(smb_fname),
5214 fsp ? fsp->fnum : -1, info_level,tran_call,total_data));
5216 /* Pull out any data sent here before we realloc. */
5217 switch (info_level) {
5218 case SMB_INFO_QUERY_EAS_FROM_LIST:
5220 /* Pull any EA list from the data portion. */
5221 uint32 ea_size;
5223 if (total_data < 4) {
5224 reply_nterror(
5225 req, NT_STATUS_INVALID_PARAMETER);
5226 return;
5228 ea_size = IVAL(pdata,0);
5230 if (total_data > 0 && ea_size != total_data) {
5231 DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
5232 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
5233 reply_nterror(
5234 req, NT_STATUS_INVALID_PARAMETER);
5235 return;
5238 if (!lp_ea_support(SNUM(conn))) {
5239 reply_doserror(req, ERRDOS,
5240 ERReasnotsupported);
5241 return;
5244 /* Pull out the list of names. */
5245 ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4);
5246 if (!ea_list) {
5247 reply_nterror(
5248 req, NT_STATUS_INVALID_PARAMETER);
5249 return;
5251 break;
5254 case SMB_QUERY_POSIX_LOCK:
5256 if (fsp == NULL || fsp->fh->fd == -1) {
5257 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5258 return;
5261 if (total_data != POSIX_LOCK_DATA_SIZE) {
5262 reply_nterror(
5263 req, NT_STATUS_INVALID_PARAMETER);
5264 return;
5267 /* Copy the lock range data. */
5268 lock_data = (char *)TALLOC_MEMDUP(
5269 req, pdata, total_data);
5270 if (!lock_data) {
5271 reply_nterror(req, NT_STATUS_NO_MEMORY);
5272 return;
5274 lock_data_count = total_data;
5276 default:
5277 break;
5280 *pparams = (char *)SMB_REALLOC(*pparams,2);
5281 if (*pparams == NULL) {
5282 reply_nterror(req, NT_STATUS_NO_MEMORY);
5283 return;
5285 params = *pparams;
5286 SSVAL(params,0,0);
5289 * draft-leach-cifs-v1-spec-02.txt
5290 * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path
5291 * says:
5293 * The requested information is placed in the Data portion of the
5294 * transaction response. For the information levels greater than 0x100,
5295 * the transaction response has 1 parameter word which should be
5296 * ignored by the client.
5298 * However Windows only follows this rule for the IS_NAME_VALID call.
5300 switch (info_level) {
5301 case SMB_INFO_IS_NAME_VALID:
5302 param_size = 0;
5303 break;
5306 if ((info_level & 0xFF00) == 0xFF00) {
5308 * We use levels that start with 0xFF00
5309 * internally to represent SMB2 specific levels
5311 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5312 return;
5315 status = smbd_do_qfilepathinfo(conn, req, info_level,
5316 fsp, smb_fname,
5317 delete_pending, write_time_ts,
5318 ms_dfs_link, ea_list,
5319 lock_data_count, lock_data,
5320 req->flags2, max_data_bytes,
5321 ppdata, &data_size);
5322 if (!NT_STATUS_IS_OK(status)) {
5323 reply_nterror(req, status);
5324 return;
5327 send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
5328 max_data_bytes);
5330 return;
5333 /****************************************************************************
5334 Set a hard link (called by UNIX extensions and by NT rename with HARD link
5335 code.
5336 ****************************************************************************/
5338 NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
5339 connection_struct *conn,
5340 const struct smb_filename *smb_fname_old,
5341 const struct smb_filename *smb_fname_new)
5343 NTSTATUS status = NT_STATUS_OK;
5345 /* source must already exist. */
5346 if (!VALID_STAT(smb_fname_old->st)) {
5347 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5350 /* Disallow if newname already exists. */
5351 if (VALID_STAT(smb_fname_new->st)) {
5352 return NT_STATUS_OBJECT_NAME_COLLISION;
5355 /* No links from a directory. */
5356 if (S_ISDIR(smb_fname_old->st.st_ex_mode)) {
5357 return NT_STATUS_FILE_IS_A_DIRECTORY;
5360 /* Setting a hardlink to/from a stream isn't currently supported. */
5361 if (is_ntfs_stream_smb_fname(smb_fname_old) ||
5362 is_ntfs_stream_smb_fname(smb_fname_new)) {
5363 return NT_STATUS_INVALID_PARAMETER;
5366 DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n",
5367 smb_fname_old->base_name, smb_fname_new->base_name));
5369 if (SMB_VFS_LINK(conn, smb_fname_old->base_name,
5370 smb_fname_new->base_name) != 0) {
5371 status = map_nt_error_from_unix(errno);
5372 DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
5373 nt_errstr(status), smb_fname_old->base_name,
5374 smb_fname_new->base_name));
5376 return status;
5379 /****************************************************************************
5380 Deal with setting the time from any of the setfilepathinfo functions.
5381 ****************************************************************************/
5383 NTSTATUS smb_set_file_time(connection_struct *conn,
5384 files_struct *fsp,
5385 const struct smb_filename *smb_fname,
5386 struct smb_file_time *ft,
5387 bool setting_write_time)
5389 struct smb_filename smb_fname_base;
5390 uint32 action =
5391 FILE_NOTIFY_CHANGE_LAST_ACCESS
5392 |FILE_NOTIFY_CHANGE_LAST_WRITE
5393 |FILE_NOTIFY_CHANGE_CREATION;
5395 if (!VALID_STAT(smb_fname->st)) {
5396 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5399 /* get some defaults (no modifications) if any info is zero or -1. */
5400 if (null_timespec(ft->create_time)) {
5401 action &= ~FILE_NOTIFY_CHANGE_CREATION;
5404 if (null_timespec(ft->atime)) {
5405 action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
5408 if (null_timespec(ft->mtime)) {
5409 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
5412 if (!setting_write_time) {
5413 /* ft->mtime comes from change time, not write time. */
5414 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
5417 /* Ensure the resolution is the correct for
5418 * what we can store on this filesystem. */
5420 round_timespec(conn->ts_res, &ft->create_time);
5421 round_timespec(conn->ts_res, &ft->ctime);
5422 round_timespec(conn->ts_res, &ft->atime);
5423 round_timespec(conn->ts_res, &ft->mtime);
5425 DEBUG(5,("smb_set_filetime: actime: %s\n ",
5426 time_to_asc(convert_timespec_to_time_t(ft->atime))));
5427 DEBUG(5,("smb_set_filetime: modtime: %s\n ",
5428 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
5429 DEBUG(5,("smb_set_filetime: ctime: %s\n ",
5430 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
5431 DEBUG(5,("smb_set_file_time: createtime: %s\n ",
5432 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
5434 if (setting_write_time) {
5436 * This was a Windows setfileinfo on an open file.
5437 * NT does this a lot. We also need to
5438 * set the time here, as it can be read by
5439 * FindFirst/FindNext and with the patch for bug #2045
5440 * in smbd/fileio.c it ensures that this timestamp is
5441 * kept sticky even after a write. We save the request
5442 * away and will set it on file close and after a write. JRA.
5445 DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n",
5446 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
5448 if (fsp != NULL) {
5449 if (fsp->base_fsp) {
5450 set_sticky_write_time_fsp(fsp->base_fsp,
5451 ft->mtime);
5452 } else {
5453 set_sticky_write_time_fsp(fsp, ft->mtime);
5455 } else {
5456 set_sticky_write_time_path(
5457 vfs_file_id_from_sbuf(conn, &smb_fname->st),
5458 ft->mtime);
5462 DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
5464 /* Always call ntimes on the base, even if a stream was passed in. */
5465 smb_fname_base = *smb_fname;
5466 smb_fname_base.stream_name = NULL;
5468 if(file_ntimes(conn, &smb_fname_base, ft)!=0) {
5469 return map_nt_error_from_unix(errno);
5472 notify_fname(conn, NOTIFY_ACTION_MODIFIED, action,
5473 smb_fname->base_name);
5474 return NT_STATUS_OK;
5477 /****************************************************************************
5478 Deal with setting the dosmode from any of the setfilepathinfo functions.
5479 ****************************************************************************/
5481 static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
5482 const struct smb_filename *smb_fname,
5483 uint32 dosmode)
5485 struct smb_filename *smb_fname_base = NULL;
5486 NTSTATUS status;
5488 if (!VALID_STAT(smb_fname->st)) {
5489 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5492 /* Always operate on the base_name, even if a stream was passed in. */
5493 status = create_synthetic_smb_fname(talloc_tos(), smb_fname->base_name,
5494 NULL, &smb_fname->st,
5495 &smb_fname_base);
5496 if (!NT_STATUS_IS_OK(status)) {
5497 return status;
5500 if (dosmode) {
5501 if (S_ISDIR(smb_fname_base->st.st_ex_mode)) {
5502 dosmode |= aDIR;
5503 } else {
5504 dosmode &= ~aDIR;
5508 DEBUG(6,("smb_set_file_dosmode: dosmode: 0x%x\n", (unsigned int)dosmode));
5510 /* check the mode isn't different, before changing it */
5511 if ((dosmode != 0) && (dosmode != dos_mode(conn, smb_fname_base))) {
5512 DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode "
5513 "0x%x\n", smb_fname_str_dbg(smb_fname_base),
5514 (unsigned int)dosmode));
5516 if(file_set_dosmode(conn, smb_fname_base, dosmode, NULL,
5517 false)) {
5518 DEBUG(2,("smb_set_file_dosmode: file_set_dosmode of "
5519 "%s failed (%s)\n",
5520 smb_fname_str_dbg(smb_fname_base),
5521 strerror(errno)));
5522 status = map_nt_error_from_unix(errno);
5523 goto out;
5526 status = NT_STATUS_OK;
5527 out:
5528 TALLOC_FREE(smb_fname_base);
5529 return status;
5532 /****************************************************************************
5533 Deal with setting the size from any of the setfilepathinfo functions.
5534 ****************************************************************************/
5536 static NTSTATUS smb_set_file_size(connection_struct *conn,
5537 struct smb_request *req,
5538 files_struct *fsp,
5539 const struct smb_filename *smb_fname,
5540 const SMB_STRUCT_STAT *psbuf,
5541 SMB_OFF_T size,
5542 bool fail_after_createfile)
5544 NTSTATUS status = NT_STATUS_OK;
5545 struct smb_filename *smb_fname_tmp = NULL;
5546 files_struct *new_fsp = NULL;
5548 if (!VALID_STAT(*psbuf)) {
5549 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5552 DEBUG(6,("smb_set_file_size: size: %.0f ", (double)size));
5554 if (size == get_file_size_stat(psbuf)) {
5555 return NT_STATUS_OK;
5558 DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n",
5559 smb_fname_str_dbg(smb_fname), (double)size));
5561 if (fsp && fsp->fh->fd != -1) {
5562 /* Handle based call. */
5563 if (vfs_set_filelen(fsp, size) == -1) {
5564 return map_nt_error_from_unix(errno);
5566 trigger_write_time_update_immediate(fsp);
5567 return NT_STATUS_OK;
5570 status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
5571 if (!NT_STATUS_IS_OK(status)) {
5572 return status;
5575 smb_fname_tmp->st = *psbuf;
5577 status = SMB_VFS_CREATE_FILE(
5578 conn, /* conn */
5579 req, /* req */
5580 0, /* root_dir_fid */
5581 smb_fname_tmp, /* fname */
5582 FILE_WRITE_DATA, /* access_mask */
5583 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5584 FILE_SHARE_DELETE),
5585 FILE_OPEN, /* create_disposition*/
5586 0, /* create_options */
5587 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
5588 FORCE_OPLOCK_BREAK_TO_NONE, /* oplock_request */
5589 0, /* allocation_size */
5590 NULL, /* sd */
5591 NULL, /* ea_list */
5592 &new_fsp, /* result */
5593 NULL); /* pinfo */
5595 TALLOC_FREE(smb_fname_tmp);
5597 if (!NT_STATUS_IS_OK(status)) {
5598 /* NB. We check for open_was_deferred in the caller. */
5599 return status;
5602 /* See RAW-SFILEINFO-END-OF-FILE */
5603 if (fail_after_createfile) {
5604 close_file(req, new_fsp,NORMAL_CLOSE);
5605 return NT_STATUS_INVALID_LEVEL;
5608 if (vfs_set_filelen(new_fsp, size) == -1) {
5609 status = map_nt_error_from_unix(errno);
5610 close_file(req, new_fsp,NORMAL_CLOSE);
5611 return status;
5614 trigger_write_time_update_immediate(new_fsp);
5615 close_file(req, new_fsp,NORMAL_CLOSE);
5616 return NT_STATUS_OK;
5619 /****************************************************************************
5620 Deal with SMB_INFO_SET_EA.
5621 ****************************************************************************/
5623 static NTSTATUS smb_info_set_ea(connection_struct *conn,
5624 const char *pdata,
5625 int total_data,
5626 files_struct *fsp,
5627 const struct smb_filename *smb_fname)
5629 struct ea_list *ea_list = NULL;
5630 TALLOC_CTX *ctx = NULL;
5631 NTSTATUS status = NT_STATUS_OK;
5633 if (total_data < 10) {
5635 /* OS/2 workplace shell seems to send SET_EA requests of "null"
5636 length. They seem to have no effect. Bug #3212. JRA */
5638 if ((total_data == 4) && (IVAL(pdata,0) == 4)) {
5639 /* We're done. We only get EA info in this call. */
5640 return NT_STATUS_OK;
5643 return NT_STATUS_INVALID_PARAMETER;
5646 if (IVAL(pdata,0) > total_data) {
5647 DEBUG(10,("smb_info_set_ea: bad total data size (%u) > %u\n",
5648 IVAL(pdata,0), (unsigned int)total_data));
5649 return NT_STATUS_INVALID_PARAMETER;
5652 ctx = talloc_tos();
5653 ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
5654 if (!ea_list) {
5655 return NT_STATUS_INVALID_PARAMETER;
5657 status = set_ea(conn, fsp, smb_fname, ea_list);
5659 return status;
5662 /****************************************************************************
5663 Deal with SMB_FILE_FULL_EA_INFORMATION set.
5664 ****************************************************************************/
5666 static NTSTATUS smb_set_file_full_ea_info(connection_struct *conn,
5667 const char *pdata,
5668 int total_data,
5669 files_struct *fsp)
5671 struct ea_list *ea_list = NULL;
5672 NTSTATUS status;
5674 if (!fsp) {
5675 return NT_STATUS_INVALID_HANDLE;
5678 if (!lp_ea_support(SNUM(conn))) {
5679 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u but "
5680 "EA's not supported.\n",
5681 (unsigned int)total_data));
5682 return NT_STATUS_EAS_NOT_SUPPORTED;
5685 if (total_data < 10) {
5686 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u "
5687 "too small.\n",
5688 (unsigned int)total_data));
5689 return NT_STATUS_INVALID_PARAMETER;
5692 ea_list = read_nttrans_ea_list(talloc_tos(),
5693 pdata,
5694 total_data);
5696 if (!ea_list) {
5697 return NT_STATUS_INVALID_PARAMETER;
5699 status = set_ea(conn, fsp, fsp->fsp_name, ea_list);
5701 DEBUG(10, ("smb_set_file_full_ea_info on file %s returned %s\n",
5702 smb_fname_str_dbg(fsp->fsp_name),
5703 nt_errstr(status) ));
5705 return status;
5709 /****************************************************************************
5710 Deal with SMB_SET_FILE_DISPOSITION_INFO.
5711 ****************************************************************************/
5713 static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
5714 const char *pdata,
5715 int total_data,
5716 files_struct *fsp,
5717 struct smb_filename *smb_fname)
5719 NTSTATUS status = NT_STATUS_OK;
5720 bool delete_on_close;
5721 uint32 dosmode = 0;
5723 if (total_data < 1) {
5724 return NT_STATUS_INVALID_PARAMETER;
5727 if (fsp == NULL) {
5728 return NT_STATUS_INVALID_HANDLE;
5731 delete_on_close = (CVAL(pdata,0) ? True : False);
5732 dosmode = dos_mode(conn, smb_fname);
5734 DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
5735 "delete_on_close = %u\n",
5736 smb_fname_str_dbg(smb_fname),
5737 (unsigned int)dosmode,
5738 (unsigned int)delete_on_close ));
5740 if (delete_on_close) {
5741 status = can_set_delete_on_close(fsp, dosmode);
5742 if (!NT_STATUS_IS_OK(status)) {
5743 return status;
5747 /* The set is across all open files on this dev/inode pair. */
5748 if (!set_delete_on_close(fsp, delete_on_close,
5749 &conn->server_info->utok)) {
5750 return NT_STATUS_ACCESS_DENIED;
5752 return NT_STATUS_OK;
5755 /****************************************************************************
5756 Deal with SMB_FILE_POSITION_INFORMATION.
5757 ****************************************************************************/
5759 static NTSTATUS smb_file_position_information(connection_struct *conn,
5760 const char *pdata,
5761 int total_data,
5762 files_struct *fsp)
5764 uint64_t position_information;
5766 if (total_data < 8) {
5767 return NT_STATUS_INVALID_PARAMETER;
5770 if (fsp == NULL) {
5771 /* Ignore on pathname based set. */
5772 return NT_STATUS_OK;
5775 position_information = (uint64_t)IVAL(pdata,0);
5776 #ifdef LARGE_SMB_OFF_T
5777 position_information |= (((uint64_t)IVAL(pdata,4)) << 32);
5778 #else /* LARGE_SMB_OFF_T */
5779 if (IVAL(pdata,4) != 0) {
5780 /* more than 32 bits? */
5781 return NT_STATUS_INVALID_PARAMETER;
5783 #endif /* LARGE_SMB_OFF_T */
5785 DEBUG(10,("smb_file_position_information: Set file position "
5786 "information for file %s to %.0f\n", fsp_str_dbg(fsp),
5787 (double)position_information));
5788 fsp->fh->position_information = position_information;
5789 return NT_STATUS_OK;
5792 /****************************************************************************
5793 Deal with SMB_FILE_MODE_INFORMATION.
5794 ****************************************************************************/
5796 static NTSTATUS smb_file_mode_information(connection_struct *conn,
5797 const char *pdata,
5798 int total_data)
5800 uint32 mode;
5802 if (total_data < 4) {
5803 return NT_STATUS_INVALID_PARAMETER;
5805 mode = IVAL(pdata,0);
5806 if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
5807 return NT_STATUS_INVALID_PARAMETER;
5809 return NT_STATUS_OK;
5812 /****************************************************************************
5813 Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
5814 ****************************************************************************/
5816 static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
5817 struct smb_request *req,
5818 const char *pdata,
5819 int total_data,
5820 const struct smb_filename *smb_fname)
5822 char *link_target = NULL;
5823 const char *newname = smb_fname->base_name;
5824 NTSTATUS status = NT_STATUS_OK;
5825 TALLOC_CTX *ctx = talloc_tos();
5827 /* Set a symbolic link. */
5828 /* Don't allow this if follow links is false. */
5830 if (total_data == 0) {
5831 return NT_STATUS_INVALID_PARAMETER;
5834 if (!lp_symlinks(SNUM(conn))) {
5835 return NT_STATUS_ACCESS_DENIED;
5838 srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
5839 total_data, STR_TERMINATE);
5841 if (!link_target) {
5842 return NT_STATUS_INVALID_PARAMETER;
5845 /* !widelinks forces the target path to be within the share. */
5846 /* This means we can interpret the target as a pathname. */
5847 if (!lp_widelinks(SNUM(conn))) {
5848 char *rel_name = NULL;
5849 char *last_dirp = NULL;
5851 if (*link_target == '/') {
5852 /* No absolute paths allowed. */
5853 return NT_STATUS_ACCESS_DENIED;
5855 rel_name = talloc_strdup(ctx,newname);
5856 if (!rel_name) {
5857 return NT_STATUS_NO_MEMORY;
5859 last_dirp = strrchr_m(rel_name, '/');
5860 if (last_dirp) {
5861 last_dirp[1] = '\0';
5862 } else {
5863 rel_name = talloc_strdup(ctx,"./");
5864 if (!rel_name) {
5865 return NT_STATUS_NO_MEMORY;
5868 rel_name = talloc_asprintf_append(rel_name,
5869 "%s",
5870 link_target);
5871 if (!rel_name) {
5872 return NT_STATUS_NO_MEMORY;
5875 status = check_name(conn, rel_name);
5876 if (!NT_STATUS_IS_OK(status)) {
5877 return status;
5881 DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
5882 newname, link_target ));
5884 if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0) {
5885 return map_nt_error_from_unix(errno);
5888 return NT_STATUS_OK;
5891 /****************************************************************************
5892 Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
5893 ****************************************************************************/
5895 static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
5896 struct smb_request *req,
5897 const char *pdata, int total_data,
5898 const struct smb_filename *smb_fname_new)
5900 char *oldname = NULL;
5901 struct smb_filename *smb_fname_old = NULL;
5902 TALLOC_CTX *ctx = talloc_tos();
5903 NTSTATUS status = NT_STATUS_OK;
5905 /* Set a hard link. */
5906 if (total_data == 0) {
5907 return NT_STATUS_INVALID_PARAMETER;
5910 srvstr_get_path(ctx, pdata, req->flags2, &oldname, pdata,
5911 total_data, STR_TERMINATE, &status);
5912 if (!NT_STATUS_IS_OK(status)) {
5913 return status;
5916 DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
5917 smb_fname_str_dbg(smb_fname_new), oldname));
5919 status = filename_convert(ctx,
5920 conn,
5921 req->flags2 & FLAGS2_DFS_PATHNAMES,
5922 oldname,
5924 NULL,
5925 &smb_fname_old);
5926 if (!NT_STATUS_IS_OK(status)) {
5927 return status;
5930 return hardlink_internals(ctx, conn, smb_fname_old, smb_fname_new);
5933 /****************************************************************************
5934 Deal with SMB_FILE_RENAME_INFORMATION.
5935 ****************************************************************************/
5937 static NTSTATUS smb_file_rename_information(connection_struct *conn,
5938 struct smb_request *req,
5939 const char *pdata,
5940 int total_data,
5941 files_struct *fsp,
5942 struct smb_filename *smb_fname_src)
5944 bool overwrite;
5945 uint32 root_fid;
5946 uint32 len;
5947 char *newname = NULL;
5948 struct smb_filename *smb_fname_dst = NULL;
5949 bool dest_has_wcard = False;
5950 NTSTATUS status = NT_STATUS_OK;
5951 char *p;
5952 TALLOC_CTX *ctx = talloc_tos();
5954 if (total_data < 13) {
5955 return NT_STATUS_INVALID_PARAMETER;
5958 overwrite = (CVAL(pdata,0) ? True : False);
5959 root_fid = IVAL(pdata,4);
5960 len = IVAL(pdata,8);
5962 if (len > (total_data - 12) || (len == 0) || (root_fid != 0)) {
5963 return NT_STATUS_INVALID_PARAMETER;
5966 srvstr_get_path_wcard(ctx, pdata, req->flags2, &newname, &pdata[12],
5967 len, 0, &status,
5968 &dest_has_wcard);
5969 if (!NT_STATUS_IS_OK(status)) {
5970 return status;
5973 DEBUG(10,("smb_file_rename_information: got name |%s|\n",
5974 newname));
5976 status = resolve_dfspath_wcard(ctx, conn,
5977 req->flags2 & FLAGS2_DFS_PATHNAMES,
5978 newname,
5979 &newname,
5980 &dest_has_wcard);
5981 if (!NT_STATUS_IS_OK(status)) {
5982 return status;
5985 /* Check the new name has no '/' characters. */
5986 if (strchr_m(newname, '/')) {
5987 return NT_STATUS_NOT_SUPPORTED;
5990 if (fsp && fsp->base_fsp) {
5991 /* newname must be a stream name. */
5992 if (newname[0] != ':') {
5993 return NT_STATUS_NOT_SUPPORTED;
5996 /* Create an smb_fname to call rename_internals_fsp() with. */
5997 status = create_synthetic_smb_fname(talloc_tos(),
5998 fsp->base_fsp->fsp_name->base_name, newname, NULL,
5999 &smb_fname_dst);
6000 if (!NT_STATUS_IS_OK(status)) {
6001 goto out;
6005 * Set the original last component, since
6006 * rename_internals_fsp() requires it.
6008 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6009 newname);
6010 if (smb_fname_dst->original_lcomp == NULL) {
6011 status = NT_STATUS_NO_MEMORY;
6012 goto out;
6015 } else {
6017 * Build up an smb_fname_dst based on the filename passed in.
6018 * We basically just strip off the last component, and put on
6019 * the newname instead.
6021 char *base_name = NULL;
6023 /* newname must *not* be a stream name. */
6024 if (newname[0] == ':') {
6025 return NT_STATUS_NOT_SUPPORTED;
6029 * Strip off the last component (filename) of the path passed
6030 * in.
6032 base_name = talloc_strdup(ctx, smb_fname_src->base_name);
6033 if (!base_name) {
6034 return NT_STATUS_NO_MEMORY;
6036 p = strrchr_m(base_name, '/');
6037 if (p) {
6038 p[1] = '\0';
6039 } else {
6040 base_name = talloc_strdup(ctx, "./");
6041 if (!base_name) {
6042 return NT_STATUS_NO_MEMORY;
6045 /* Append the new name. */
6046 base_name = talloc_asprintf_append(base_name,
6047 "%s",
6048 newname);
6049 if (!base_name) {
6050 return NT_STATUS_NO_MEMORY;
6053 status = unix_convert(ctx, conn, base_name, &smb_fname_dst,
6054 (UCF_SAVE_LCOMP |
6055 (dest_has_wcard ?
6056 UCF_ALWAYS_ALLOW_WCARD_LCOMP :
6057 0)));
6059 /* If an error we expect this to be
6060 * NT_STATUS_OBJECT_PATH_NOT_FOUND */
6062 if (!NT_STATUS_IS_OK(status)) {
6063 if(!NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
6064 status)) {
6065 goto out;
6067 /* Create an smb_fname to call rename_internals_fsp() */
6068 status = create_synthetic_smb_fname(ctx,
6069 base_name, NULL,
6070 NULL,
6071 &smb_fname_dst);
6072 if (!NT_STATUS_IS_OK(status)) {
6073 goto out;
6078 if (fsp) {
6079 DEBUG(10,("smb_file_rename_information: "
6080 "SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
6081 fsp->fnum, fsp_str_dbg(fsp),
6082 smb_fname_str_dbg(smb_fname_dst)));
6083 status = rename_internals_fsp(conn, fsp, smb_fname_dst, 0,
6084 overwrite);
6085 } else {
6086 DEBUG(10,("smb_file_rename_information: "
6087 "SMB_FILE_RENAME_INFORMATION %s -> %s\n",
6088 smb_fname_str_dbg(smb_fname_src),
6089 smb_fname_str_dbg(smb_fname_dst)));
6090 status = rename_internals(ctx, conn, req, smb_fname_src,
6091 smb_fname_dst, 0, overwrite, false,
6092 dest_has_wcard,
6093 FILE_WRITE_ATTRIBUTES);
6095 out:
6096 TALLOC_FREE(smb_fname_dst);
6097 return status;
6100 /****************************************************************************
6101 Deal with SMB_SET_POSIX_ACL.
6102 ****************************************************************************/
6104 #if defined(HAVE_POSIX_ACLS)
6105 static NTSTATUS smb_set_posix_acl(connection_struct *conn,
6106 const char *pdata,
6107 int total_data,
6108 files_struct *fsp,
6109 const struct smb_filename *smb_fname)
6111 uint16 posix_acl_version;
6112 uint16 num_file_acls;
6113 uint16 num_def_acls;
6114 bool valid_file_acls = True;
6115 bool valid_def_acls = True;
6117 if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
6118 return NT_STATUS_INVALID_PARAMETER;
6120 posix_acl_version = SVAL(pdata,0);
6121 num_file_acls = SVAL(pdata,2);
6122 num_def_acls = SVAL(pdata,4);
6124 if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
6125 valid_file_acls = False;
6126 num_file_acls = 0;
6129 if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
6130 valid_def_acls = False;
6131 num_def_acls = 0;
6134 if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
6135 return NT_STATUS_INVALID_PARAMETER;
6138 if (total_data < SMB_POSIX_ACL_HEADER_SIZE +
6139 (num_file_acls+num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE) {
6140 return NT_STATUS_INVALID_PARAMETER;
6143 DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
6144 smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
6145 (unsigned int)num_file_acls,
6146 (unsigned int)num_def_acls));
6148 if (valid_file_acls && !set_unix_posix_acl(conn, fsp,
6149 smb_fname->base_name, num_file_acls,
6150 pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
6151 return map_nt_error_from_unix(errno);
6154 if (valid_def_acls && !set_unix_posix_default_acl(conn,
6155 smb_fname->base_name, &smb_fname->st, num_def_acls,
6156 pdata + SMB_POSIX_ACL_HEADER_SIZE +
6157 (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) {
6158 return map_nt_error_from_unix(errno);
6160 return NT_STATUS_OK;
6162 #endif
6164 /****************************************************************************
6165 Deal with SMB_SET_POSIX_LOCK.
6166 ****************************************************************************/
6168 static NTSTATUS smb_set_posix_lock(connection_struct *conn,
6169 struct smb_request *req,
6170 const char *pdata,
6171 int total_data,
6172 files_struct *fsp)
6174 uint64_t count;
6175 uint64_t offset;
6176 uint32 lock_pid;
6177 bool blocking_lock = False;
6178 enum brl_type lock_type;
6180 NTSTATUS status = NT_STATUS_OK;
6182 if (fsp == NULL || fsp->fh->fd == -1) {
6183 return NT_STATUS_INVALID_HANDLE;
6186 if (total_data != POSIX_LOCK_DATA_SIZE) {
6187 return NT_STATUS_INVALID_PARAMETER;
6190 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
6191 case POSIX_LOCK_TYPE_READ:
6192 lock_type = READ_LOCK;
6193 break;
6194 case POSIX_LOCK_TYPE_WRITE:
6195 /* Return the right POSIX-mappable error code for files opened read-only. */
6196 if (!fsp->can_write) {
6197 return NT_STATUS_INVALID_HANDLE;
6199 lock_type = WRITE_LOCK;
6200 break;
6201 case POSIX_LOCK_TYPE_UNLOCK:
6202 lock_type = UNLOCK_LOCK;
6203 break;
6204 default:
6205 return NT_STATUS_INVALID_PARAMETER;
6208 if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
6209 blocking_lock = False;
6210 } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
6211 blocking_lock = True;
6212 } else {
6213 return NT_STATUS_INVALID_PARAMETER;
6216 if (!lp_blocking_locks(SNUM(conn))) {
6217 blocking_lock = False;
6220 lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
6221 #if defined(HAVE_LONGLONG)
6222 offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
6223 ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
6224 count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
6225 ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
6226 #else /* HAVE_LONGLONG */
6227 offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET);
6228 count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
6229 #endif /* HAVE_LONGLONG */
6231 DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u,"
6232 "lock_pid = %u, count = %.0f, offset = %.0f\n",
6233 fsp_str_dbg(fsp),
6234 (unsigned int)lock_type,
6235 (unsigned int)lock_pid,
6236 (double)count,
6237 (double)offset ));
6239 if (lock_type == UNLOCK_LOCK) {
6240 status = do_unlock(smbd_messaging_context(),
6241 fsp,
6242 lock_pid,
6243 count,
6244 offset,
6245 POSIX_LOCK);
6246 } else {
6247 uint32 block_smbpid;
6249 struct byte_range_lock *br_lck = do_lock(smbd_messaging_context(),
6250 fsp,
6251 lock_pid,
6252 count,
6253 offset,
6254 lock_type,
6255 POSIX_LOCK,
6256 blocking_lock,
6257 &status,
6258 &block_smbpid,
6259 NULL);
6261 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
6263 * A blocking lock was requested. Package up
6264 * this smb into a queued request and push it
6265 * onto the blocking lock queue.
6267 if(push_blocking_lock_request(br_lck,
6268 req,
6269 fsp,
6270 -1, /* infinite timeout. */
6272 lock_pid,
6273 lock_type,
6274 POSIX_LOCK,
6275 offset,
6276 count,
6277 block_smbpid)) {
6278 TALLOC_FREE(br_lck);
6279 return status;
6282 TALLOC_FREE(br_lck);
6285 return status;
6288 /****************************************************************************
6289 Deal with SMB_SET_FILE_BASIC_INFO.
6290 ****************************************************************************/
6292 static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
6293 const char *pdata,
6294 int total_data,
6295 files_struct *fsp,
6296 const struct smb_filename *smb_fname)
6298 /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
6299 struct smb_file_time ft;
6300 uint32 dosmode = 0;
6301 NTSTATUS status = NT_STATUS_OK;
6303 ZERO_STRUCT(ft);
6305 if (total_data < 36) {
6306 return NT_STATUS_INVALID_PARAMETER;
6309 /* Set the attributes */
6310 dosmode = IVAL(pdata,32);
6311 status = smb_set_file_dosmode(conn, smb_fname, dosmode);
6312 if (!NT_STATUS_IS_OK(status)) {
6313 return status;
6316 /* create time */
6317 ft.create_time = interpret_long_date(pdata);
6319 /* access time */
6320 ft.atime = interpret_long_date(pdata+8);
6322 /* write time. */
6323 ft.mtime = interpret_long_date(pdata+16);
6325 /* change time. */
6326 ft.ctime = interpret_long_date(pdata+24);
6328 DEBUG(10, ("smb_set_file_basic_info: file %s\n",
6329 smb_fname_str_dbg(smb_fname)));
6331 return smb_set_file_time(conn, fsp, smb_fname, &ft,
6332 true);
6335 /****************************************************************************
6336 Deal with SMB_INFO_STANDARD.
6337 ****************************************************************************/
6339 static NTSTATUS smb_set_info_standard(connection_struct *conn,
6340 const char *pdata,
6341 int total_data,
6342 files_struct *fsp,
6343 const struct smb_filename *smb_fname)
6345 struct smb_file_time ft;
6347 ZERO_STRUCT(ft);
6349 if (total_data < 12) {
6350 return NT_STATUS_INVALID_PARAMETER;
6353 /* create time */
6354 ft.create_time = convert_time_t_to_timespec(srv_make_unix_date2(pdata));
6355 /* access time */
6356 ft.atime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+4));
6357 /* write time */
6358 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+8));
6360 DEBUG(10,("smb_set_info_standard: file %s\n",
6361 smb_fname_str_dbg(smb_fname)));
6363 return smb_set_file_time(conn,
6364 fsp,
6365 smb_fname,
6366 &ft,
6367 true);
6370 /****************************************************************************
6371 Deal with SMB_SET_FILE_ALLOCATION_INFO.
6372 ****************************************************************************/
6374 static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
6375 struct smb_request *req,
6376 const char *pdata,
6377 int total_data,
6378 files_struct *fsp,
6379 struct smb_filename *smb_fname)
6381 uint64_t allocation_size = 0;
6382 NTSTATUS status = NT_STATUS_OK;
6383 files_struct *new_fsp = NULL;
6385 if (!VALID_STAT(smb_fname->st)) {
6386 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6389 if (total_data < 8) {
6390 return NT_STATUS_INVALID_PARAMETER;
6393 allocation_size = (uint64_t)IVAL(pdata,0);
6394 #ifdef LARGE_SMB_OFF_T
6395 allocation_size |= (((uint64_t)IVAL(pdata,4)) << 32);
6396 #else /* LARGE_SMB_OFF_T */
6397 if (IVAL(pdata,4) != 0) {
6398 /* more than 32 bits? */
6399 return NT_STATUS_INVALID_PARAMETER;
6401 #endif /* LARGE_SMB_OFF_T */
6403 DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for "
6404 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
6405 (double)allocation_size));
6407 if (allocation_size) {
6408 allocation_size = smb_roundup(conn, allocation_size);
6411 DEBUG(10,("smb_set_file_allocation_info: file %s : setting new "
6412 "allocation size to %.0f\n", smb_fname_str_dbg(smb_fname),
6413 (double)allocation_size));
6415 if (fsp && fsp->fh->fd != -1) {
6416 /* Open file handle. */
6417 /* Only change if needed. */
6418 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
6419 if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
6420 return map_nt_error_from_unix(errno);
6423 /* But always update the time. */
6425 * This is equivalent to a write. Ensure it's seen immediately
6426 * if there are no pending writes.
6428 trigger_write_time_update_immediate(fsp);
6429 return NT_STATUS_OK;
6432 /* Pathname or stat or directory file. */
6433 status = SMB_VFS_CREATE_FILE(
6434 conn, /* conn */
6435 req, /* req */
6436 0, /* root_dir_fid */
6437 smb_fname, /* fname */
6438 FILE_WRITE_DATA, /* access_mask */
6439 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6440 FILE_SHARE_DELETE),
6441 FILE_OPEN, /* create_disposition*/
6442 0, /* create_options */
6443 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6444 FORCE_OPLOCK_BREAK_TO_NONE, /* oplock_request */
6445 0, /* allocation_size */
6446 NULL, /* sd */
6447 NULL, /* ea_list */
6448 &new_fsp, /* result */
6449 NULL); /* pinfo */
6451 if (!NT_STATUS_IS_OK(status)) {
6452 /* NB. We check for open_was_deferred in the caller. */
6453 return status;
6456 /* Only change if needed. */
6457 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
6458 if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) {
6459 status = map_nt_error_from_unix(errno);
6460 close_file(req, new_fsp, NORMAL_CLOSE);
6461 return status;
6465 /* Changing the allocation size should set the last mod time. */
6467 * This is equivalent to a write. Ensure it's seen immediately
6468 * if there are no pending writes.
6470 trigger_write_time_update_immediate(new_fsp);
6472 close_file(req, new_fsp, NORMAL_CLOSE);
6473 return NT_STATUS_OK;
6476 /****************************************************************************
6477 Deal with SMB_SET_FILE_END_OF_FILE_INFO.
6478 ****************************************************************************/
6480 static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
6481 struct smb_request *req,
6482 const char *pdata,
6483 int total_data,
6484 files_struct *fsp,
6485 const struct smb_filename *smb_fname,
6486 bool fail_after_createfile)
6488 SMB_OFF_T size;
6490 if (total_data < 8) {
6491 return NT_STATUS_INVALID_PARAMETER;
6494 size = IVAL(pdata,0);
6495 #ifdef LARGE_SMB_OFF_T
6496 size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
6497 #else /* LARGE_SMB_OFF_T */
6498 if (IVAL(pdata,4) != 0) {
6499 /* more than 32 bits? */
6500 return NT_STATUS_INVALID_PARAMETER;
6502 #endif /* LARGE_SMB_OFF_T */
6503 DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for "
6504 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
6505 (double)size));
6507 return smb_set_file_size(conn, req,
6508 fsp,
6509 smb_fname,
6510 &smb_fname->st,
6511 size,
6512 fail_after_createfile);
6515 /****************************************************************************
6516 Allow a UNIX info mknod.
6517 ****************************************************************************/
6519 static NTSTATUS smb_unix_mknod(connection_struct *conn,
6520 const char *pdata,
6521 int total_data,
6522 const struct smb_filename *smb_fname)
6524 uint32 file_type = IVAL(pdata,56);
6525 #if defined(HAVE_MAKEDEV)
6526 uint32 dev_major = IVAL(pdata,60);
6527 uint32 dev_minor = IVAL(pdata,68);
6528 #endif
6529 SMB_DEV_T dev = (SMB_DEV_T)0;
6530 uint32 raw_unixmode = IVAL(pdata,84);
6531 NTSTATUS status;
6532 mode_t unixmode;
6534 if (total_data < 100) {
6535 return NT_STATUS_INVALID_PARAMETER;
6538 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6539 PERM_NEW_FILE, &unixmode);
6540 if (!NT_STATUS_IS_OK(status)) {
6541 return status;
6544 #if defined(HAVE_MAKEDEV)
6545 dev = makedev(dev_major, dev_minor);
6546 #endif
6548 switch (file_type) {
6549 #if defined(S_IFIFO)
6550 case UNIX_TYPE_FIFO:
6551 unixmode |= S_IFIFO;
6552 break;
6553 #endif
6554 #if defined(S_IFSOCK)
6555 case UNIX_TYPE_SOCKET:
6556 unixmode |= S_IFSOCK;
6557 break;
6558 #endif
6559 #if defined(S_IFCHR)
6560 case UNIX_TYPE_CHARDEV:
6561 unixmode |= S_IFCHR;
6562 break;
6563 #endif
6564 #if defined(S_IFBLK)
6565 case UNIX_TYPE_BLKDEV:
6566 unixmode |= S_IFBLK;
6567 break;
6568 #endif
6569 default:
6570 return NT_STATUS_INVALID_PARAMETER;
6573 DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
6574 "%.0f mode 0%o for file %s\n", (double)dev,
6575 (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
6577 /* Ok - do the mknod. */
6578 if (SMB_VFS_MKNOD(conn, smb_fname->base_name, unixmode, dev) != 0) {
6579 return map_nt_error_from_unix(errno);
6582 /* If any of the other "set" calls fail we
6583 * don't want to end up with a half-constructed mknod.
6586 if (lp_inherit_perms(SNUM(conn))) {
6587 char *parent;
6588 if (!parent_dirname(talloc_tos(), smb_fname->base_name,
6589 &parent, NULL)) {
6590 return NT_STATUS_NO_MEMORY;
6592 inherit_access_posix_acl(conn, parent, smb_fname->base_name,
6593 unixmode);
6594 TALLOC_FREE(parent);
6597 return NT_STATUS_OK;
6600 /****************************************************************************
6601 Deal with SMB_SET_FILE_UNIX_BASIC.
6602 ****************************************************************************/
6604 static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
6605 struct smb_request *req,
6606 const char *pdata,
6607 int total_data,
6608 files_struct *fsp,
6609 const struct smb_filename *smb_fname)
6611 struct smb_file_time ft;
6612 uint32 raw_unixmode;
6613 mode_t unixmode;
6614 SMB_OFF_T size = 0;
6615 uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
6616 gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
6617 NTSTATUS status = NT_STATUS_OK;
6618 bool delete_on_fail = False;
6619 enum perm_type ptype;
6620 files_struct *all_fsps = NULL;
6621 bool modify_mtime = true;
6622 struct file_id id;
6623 SMB_STRUCT_STAT sbuf;
6625 ZERO_STRUCT(ft);
6627 if (total_data < 100) {
6628 return NT_STATUS_INVALID_PARAMETER;
6631 if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
6632 IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
6633 size=IVAL(pdata,0); /* first 8 Bytes are size */
6634 #ifdef LARGE_SMB_OFF_T
6635 size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
6636 #else /* LARGE_SMB_OFF_T */
6637 if (IVAL(pdata,4) != 0) {
6638 /* more than 32 bits? */
6639 return NT_STATUS_INVALID_PARAMETER;
6641 #endif /* LARGE_SMB_OFF_T */
6644 ft.atime = interpret_long_date(pdata+24); /* access_time */
6645 ft.mtime = interpret_long_date(pdata+32); /* modification_time */
6646 set_owner = (uid_t)IVAL(pdata,40);
6647 set_grp = (gid_t)IVAL(pdata,48);
6648 raw_unixmode = IVAL(pdata,84);
6650 if (VALID_STAT(smb_fname->st)) {
6651 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
6652 ptype = PERM_EXISTING_DIR;
6653 } else {
6654 ptype = PERM_EXISTING_FILE;
6656 } else {
6657 ptype = PERM_NEW_FILE;
6660 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6661 ptype, &unixmode);
6662 if (!NT_STATUS_IS_OK(status)) {
6663 return status;
6666 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
6667 "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
6668 smb_fname_str_dbg(smb_fname), (double)size,
6669 (unsigned int)set_owner, (unsigned int)set_grp,
6670 (int)raw_unixmode));
6672 sbuf = smb_fname->st;
6674 if (!VALID_STAT(sbuf)) {
6675 struct smb_filename *smb_fname_tmp = NULL;
6677 * The only valid use of this is to create character and block
6678 * devices, and named pipes. This is deprecated (IMHO) and
6679 * a new info level should be used for mknod. JRA.
6682 status = smb_unix_mknod(conn,
6683 pdata,
6684 total_data,
6685 smb_fname);
6686 if (!NT_STATUS_IS_OK(status)) {
6687 return status;
6690 status = copy_smb_filename(talloc_tos(), smb_fname,
6691 &smb_fname_tmp);
6692 if (!NT_STATUS_IS_OK(status)) {
6693 return status;
6696 if (SMB_VFS_STAT(conn, smb_fname_tmp) != 0) {
6697 status = map_nt_error_from_unix(errno);
6698 TALLOC_FREE(smb_fname_tmp);
6699 SMB_VFS_UNLINK(conn, smb_fname);
6700 return status;
6703 sbuf = smb_fname_tmp->st;
6704 TALLOC_FREE(smb_fname_tmp);
6706 /* Ensure we don't try and change anything else. */
6707 raw_unixmode = SMB_MODE_NO_CHANGE;
6708 size = get_file_size_stat(&sbuf);
6709 ft.atime = sbuf.st_ex_atime;
6710 ft.mtime = sbuf.st_ex_mtime;
6712 * We continue here as we might want to change the
6713 * owner uid/gid.
6715 delete_on_fail = True;
6718 #if 1
6719 /* Horrible backwards compatibility hack as an old server bug
6720 * allowed a CIFS client bug to remain unnoticed :-(. JRA.
6721 * */
6723 if (!size) {
6724 size = get_file_size_stat(&sbuf);
6726 #endif
6729 * Deal with the UNIX specific mode set.
6732 if (raw_unixmode != SMB_MODE_NO_CHANGE) {
6733 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6734 "setting mode 0%o for file %s\n",
6735 (unsigned int)unixmode,
6736 smb_fname_str_dbg(smb_fname)));
6737 if (SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode) != 0) {
6738 return map_nt_error_from_unix(errno);
6743 * Deal with the UNIX specific uid set.
6746 if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
6747 (sbuf.st_ex_uid != set_owner)) {
6748 int ret;
6750 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6751 "changing owner %u for path %s\n",
6752 (unsigned int)set_owner,
6753 smb_fname_str_dbg(smb_fname)));
6755 if (S_ISLNK(sbuf.st_ex_mode)) {
6756 ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name,
6757 set_owner, (gid_t)-1);
6758 } else {
6759 ret = SMB_VFS_CHOWN(conn, smb_fname->base_name,
6760 set_owner, (gid_t)-1);
6763 if (ret != 0) {
6764 status = map_nt_error_from_unix(errno);
6765 if (delete_on_fail) {
6766 SMB_VFS_UNLINK(conn, smb_fname);
6768 return status;
6773 * Deal with the UNIX specific gid set.
6776 if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
6777 (sbuf.st_ex_gid != set_grp)) {
6778 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6779 "changing group %u for file %s\n",
6780 (unsigned int)set_owner,
6781 smb_fname_str_dbg(smb_fname)));
6782 if (SMB_VFS_CHOWN(conn, smb_fname->base_name, (uid_t)-1,
6783 set_grp) != 0) {
6784 status = map_nt_error_from_unix(errno);
6785 if (delete_on_fail) {
6786 SMB_VFS_UNLINK(conn, smb_fname);
6788 return status;
6792 /* Deal with any size changes. */
6794 status = smb_set_file_size(conn, req,
6795 fsp,
6796 smb_fname,
6797 &sbuf,
6798 size,
6799 false);
6800 if (!NT_STATUS_IS_OK(status)) {
6801 return status;
6804 /* Deal with any time changes. */
6805 if (null_timespec(ft.mtime) && null_timespec(ft.atime)) {
6806 /* No change, don't cancel anything. */
6807 return status;
6810 id = vfs_file_id_from_sbuf(conn, &sbuf);
6811 for(all_fsps = file_find_di_first(id); all_fsps;
6812 all_fsps = file_find_di_next(all_fsps)) {
6814 * We're setting the time explicitly for UNIX.
6815 * Cancel any pending changes over all handles.
6817 all_fsps->update_write_time_on_close = false;
6818 TALLOC_FREE(all_fsps->update_write_time_event);
6822 * Override the "setting_write_time"
6823 * parameter here as it almost does what
6824 * we need. Just remember if we modified
6825 * mtime and send the notify ourselves.
6827 if (null_timespec(ft.mtime)) {
6828 modify_mtime = false;
6831 status = smb_set_file_time(conn,
6832 fsp,
6833 smb_fname,
6834 &ft,
6835 false);
6836 if (modify_mtime) {
6837 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6838 FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
6840 return status;
6843 /****************************************************************************
6844 Deal with SMB_SET_FILE_UNIX_INFO2.
6845 ****************************************************************************/
6847 static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
6848 struct smb_request *req,
6849 const char *pdata,
6850 int total_data,
6851 files_struct *fsp,
6852 const struct smb_filename *smb_fname)
6854 NTSTATUS status;
6855 uint32 smb_fflags;
6856 uint32 smb_fmask;
6858 if (total_data < 116) {
6859 return NT_STATUS_INVALID_PARAMETER;
6862 /* Start by setting all the fields that are common between UNIX_BASIC
6863 * and UNIX_INFO2.
6865 status = smb_set_file_unix_basic(conn, req, pdata, total_data,
6866 fsp, smb_fname);
6867 if (!NT_STATUS_IS_OK(status)) {
6868 return status;
6871 smb_fflags = IVAL(pdata, 108);
6872 smb_fmask = IVAL(pdata, 112);
6874 /* NB: We should only attempt to alter the file flags if the client
6875 * sends a non-zero mask.
6877 if (smb_fmask != 0) {
6878 int stat_fflags = 0;
6880 if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
6881 smb_fmask, &stat_fflags)) {
6882 /* Client asked to alter a flag we don't understand. */
6883 return NT_STATUS_INVALID_PARAMETER;
6886 if (fsp && fsp->fh->fd != -1) {
6887 /* XXX: we should be using SMB_VFS_FCHFLAGS here. */
6888 return NT_STATUS_NOT_SUPPORTED;
6889 } else {
6890 if (SMB_VFS_CHFLAGS(conn, smb_fname->base_name,
6891 stat_fflags) != 0) {
6892 return map_nt_error_from_unix(errno);
6897 /* XXX: need to add support for changing the create_time here. You
6898 * can do this for paths on Darwin with setattrlist(2). The right way
6899 * to hook this up is probably by extending the VFS utimes interface.
6902 return NT_STATUS_OK;
6905 /****************************************************************************
6906 Create a directory with POSIX semantics.
6907 ****************************************************************************/
6909 static NTSTATUS smb_posix_mkdir(connection_struct *conn,
6910 struct smb_request *req,
6911 char **ppdata,
6912 int total_data,
6913 struct smb_filename *smb_fname,
6914 int *pdata_return_size)
6916 NTSTATUS status = NT_STATUS_OK;
6917 uint32 raw_unixmode = 0;
6918 uint32 mod_unixmode = 0;
6919 mode_t unixmode = (mode_t)0;
6920 files_struct *fsp = NULL;
6921 uint16 info_level_return = 0;
6922 int info;
6923 char *pdata = *ppdata;
6925 if (total_data < 18) {
6926 return NT_STATUS_INVALID_PARAMETER;
6929 raw_unixmode = IVAL(pdata,8);
6930 /* Next 4 bytes are not yet defined. */
6932 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6933 PERM_NEW_DIR, &unixmode);
6934 if (!NT_STATUS_IS_OK(status)) {
6935 return status;
6938 mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
6940 DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
6941 smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
6943 status = SMB_VFS_CREATE_FILE(
6944 conn, /* conn */
6945 req, /* req */
6946 0, /* root_dir_fid */
6947 smb_fname, /* fname */
6948 FILE_READ_ATTRIBUTES, /* access_mask */
6949 FILE_SHARE_NONE, /* share_access */
6950 FILE_CREATE, /* create_disposition*/
6951 FILE_DIRECTORY_FILE, /* create_options */
6952 mod_unixmode, /* file_attributes */
6953 0, /* oplock_request */
6954 0, /* allocation_size */
6955 NULL, /* sd */
6956 NULL, /* ea_list */
6957 &fsp, /* result */
6958 &info); /* pinfo */
6960 if (NT_STATUS_IS_OK(status)) {
6961 close_file(req, fsp, NORMAL_CLOSE);
6964 info_level_return = SVAL(pdata,16);
6966 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
6967 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
6968 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
6969 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
6970 } else {
6971 *pdata_return_size = 12;
6974 /* Realloc the data size */
6975 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
6976 if (*ppdata == NULL) {
6977 *pdata_return_size = 0;
6978 return NT_STATUS_NO_MEMORY;
6980 pdata = *ppdata;
6982 SSVAL(pdata,0,NO_OPLOCK_RETURN);
6983 SSVAL(pdata,2,0); /* No fnum. */
6984 SIVAL(pdata,4,info); /* Was directory created. */
6986 switch (info_level_return) {
6987 case SMB_QUERY_FILE_UNIX_BASIC:
6988 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
6989 SSVAL(pdata,10,0); /* Padding. */
6990 store_file_unix_basic(conn, pdata + 12, fsp,
6991 &smb_fname->st);
6992 break;
6993 case SMB_QUERY_FILE_UNIX_INFO2:
6994 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
6995 SSVAL(pdata,10,0); /* Padding. */
6996 store_file_unix_basic_info2(conn, pdata + 12, fsp,
6997 &smb_fname->st);
6998 break;
6999 default:
7000 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
7001 SSVAL(pdata,10,0); /* Padding. */
7002 break;
7005 return status;
7008 /****************************************************************************
7009 Open/Create a file with POSIX semantics.
7010 ****************************************************************************/
7012 static NTSTATUS smb_posix_open(connection_struct *conn,
7013 struct smb_request *req,
7014 char **ppdata,
7015 int total_data,
7016 struct smb_filename *smb_fname,
7017 int *pdata_return_size)
7019 bool extended_oplock_granted = False;
7020 char *pdata = *ppdata;
7021 uint32 flags = 0;
7022 uint32 wire_open_mode = 0;
7023 uint32 raw_unixmode = 0;
7024 uint32 mod_unixmode = 0;
7025 uint32 create_disp = 0;
7026 uint32 access_mask = 0;
7027 uint32 create_options = 0;
7028 NTSTATUS status = NT_STATUS_OK;
7029 mode_t unixmode = (mode_t)0;
7030 files_struct *fsp = NULL;
7031 int oplock_request = 0;
7032 int info = 0;
7033 uint16 info_level_return = 0;
7035 if (total_data < 18) {
7036 return NT_STATUS_INVALID_PARAMETER;
7039 flags = IVAL(pdata,0);
7040 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
7041 if (oplock_request) {
7042 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
7045 wire_open_mode = IVAL(pdata,4);
7047 if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
7048 return smb_posix_mkdir(conn, req,
7049 ppdata,
7050 total_data,
7051 smb_fname,
7052 pdata_return_size);
7055 switch (wire_open_mode & SMB_ACCMODE) {
7056 case SMB_O_RDONLY:
7057 access_mask = FILE_READ_DATA;
7058 break;
7059 case SMB_O_WRONLY:
7060 access_mask = FILE_WRITE_DATA;
7061 break;
7062 case SMB_O_RDWR:
7063 access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
7064 break;
7065 default:
7066 DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
7067 (unsigned int)wire_open_mode ));
7068 return NT_STATUS_INVALID_PARAMETER;
7071 wire_open_mode &= ~SMB_ACCMODE;
7073 if((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) == (SMB_O_CREAT | SMB_O_EXCL)) {
7074 create_disp = FILE_CREATE;
7075 } else if((wire_open_mode & (SMB_O_CREAT | SMB_O_TRUNC)) == (SMB_O_CREAT | SMB_O_TRUNC)) {
7076 create_disp = FILE_OVERWRITE_IF;
7077 } else if((wire_open_mode & SMB_O_CREAT) == SMB_O_CREAT) {
7078 create_disp = FILE_OPEN_IF;
7079 } else if ((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL | SMB_O_TRUNC)) == 0) {
7080 create_disp = FILE_OPEN;
7081 } else {
7082 DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
7083 (unsigned int)wire_open_mode ));
7084 return NT_STATUS_INVALID_PARAMETER;
7087 raw_unixmode = IVAL(pdata,8);
7088 /* Next 4 bytes are not yet defined. */
7090 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
7091 (VALID_STAT(smb_fname->st) ?
7092 PERM_EXISTING_FILE : PERM_NEW_FILE),
7093 &unixmode);
7095 if (!NT_STATUS_IS_OK(status)) {
7096 return status;
7099 mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
7101 if (wire_open_mode & SMB_O_SYNC) {
7102 create_options |= FILE_WRITE_THROUGH;
7104 if (wire_open_mode & SMB_O_APPEND) {
7105 access_mask |= FILE_APPEND_DATA;
7107 if (wire_open_mode & SMB_O_DIRECT) {
7108 mod_unixmode |= FILE_FLAG_NO_BUFFERING;
7111 DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
7112 smb_fname_str_dbg(smb_fname),
7113 (unsigned int)wire_open_mode,
7114 (unsigned int)unixmode ));
7116 status = SMB_VFS_CREATE_FILE(
7117 conn, /* conn */
7118 req, /* req */
7119 0, /* root_dir_fid */
7120 smb_fname, /* fname */
7121 access_mask, /* access_mask */
7122 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7123 FILE_SHARE_DELETE),
7124 create_disp, /* create_disposition*/
7125 FILE_NON_DIRECTORY_FILE, /* create_options */
7126 mod_unixmode, /* file_attributes */
7127 oplock_request, /* oplock_request */
7128 0, /* allocation_size */
7129 NULL, /* sd */
7130 NULL, /* ea_list */
7131 &fsp, /* result */
7132 &info); /* pinfo */
7134 if (!NT_STATUS_IS_OK(status)) {
7135 return status;
7138 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
7139 extended_oplock_granted = True;
7142 if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
7143 extended_oplock_granted = True;
7146 info_level_return = SVAL(pdata,16);
7148 /* Allocate the correct return size. */
7150 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
7151 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
7152 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
7153 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
7154 } else {
7155 *pdata_return_size = 12;
7158 /* Realloc the data size */
7159 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
7160 if (*ppdata == NULL) {
7161 close_file(req, fsp, ERROR_CLOSE);
7162 *pdata_return_size = 0;
7163 return NT_STATUS_NO_MEMORY;
7165 pdata = *ppdata;
7167 if (extended_oplock_granted) {
7168 if (flags & REQUEST_BATCH_OPLOCK) {
7169 SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
7170 } else {
7171 SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
7173 } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
7174 SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
7175 } else {
7176 SSVAL(pdata,0,NO_OPLOCK_RETURN);
7179 SSVAL(pdata,2,fsp->fnum);
7180 SIVAL(pdata,4,info); /* Was file created etc. */
7182 switch (info_level_return) {
7183 case SMB_QUERY_FILE_UNIX_BASIC:
7184 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
7185 SSVAL(pdata,10,0); /* padding. */
7186 store_file_unix_basic(conn, pdata + 12, fsp,
7187 &smb_fname->st);
7188 break;
7189 case SMB_QUERY_FILE_UNIX_INFO2:
7190 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
7191 SSVAL(pdata,10,0); /* padding. */
7192 store_file_unix_basic_info2(conn, pdata + 12, fsp,
7193 &smb_fname->st);
7194 break;
7195 default:
7196 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
7197 SSVAL(pdata,10,0); /* padding. */
7198 break;
7200 return NT_STATUS_OK;
7203 /****************************************************************************
7204 Delete a file with POSIX semantics.
7205 ****************************************************************************/
7207 static NTSTATUS smb_posix_unlink(connection_struct *conn,
7208 struct smb_request *req,
7209 const char *pdata,
7210 int total_data,
7211 struct smb_filename *smb_fname)
7213 NTSTATUS status = NT_STATUS_OK;
7214 files_struct *fsp = NULL;
7215 uint16 flags = 0;
7216 char del = 1;
7217 int info = 0;
7218 int create_options = 0;
7219 int i;
7220 struct share_mode_lock *lck = NULL;
7222 if (total_data < 2) {
7223 return NT_STATUS_INVALID_PARAMETER;
7226 flags = SVAL(pdata,0);
7228 if (!VALID_STAT(smb_fname->st)) {
7229 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
7232 if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
7233 !VALID_STAT_OF_DIR(smb_fname->st)) {
7234 return NT_STATUS_NOT_A_DIRECTORY;
7237 DEBUG(10,("smb_posix_unlink: %s %s\n",
7238 (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
7239 smb_fname_str_dbg(smb_fname)));
7241 if (VALID_STAT_OF_DIR(smb_fname->st)) {
7242 create_options |= FILE_DIRECTORY_FILE;
7245 status = SMB_VFS_CREATE_FILE(
7246 conn, /* conn */
7247 req, /* req */
7248 0, /* root_dir_fid */
7249 smb_fname, /* fname */
7250 DELETE_ACCESS, /* access_mask */
7251 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7252 FILE_SHARE_DELETE),
7253 FILE_OPEN, /* create_disposition*/
7254 create_options, /* create_options */
7255 FILE_FLAG_POSIX_SEMANTICS|0777, /* file_attributes */
7256 0, /* oplock_request */
7257 0, /* allocation_size */
7258 NULL, /* sd */
7259 NULL, /* ea_list */
7260 &fsp, /* result */
7261 &info); /* pinfo */
7263 if (!NT_STATUS_IS_OK(status)) {
7264 return status;
7268 * Don't lie to client. If we can't really delete due to
7269 * non-POSIX opens return SHARING_VIOLATION.
7272 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
7273 NULL);
7274 if (lck == NULL) {
7275 DEBUG(0, ("smb_posix_unlink: Could not get share mode "
7276 "lock for file %s\n", fsp_str_dbg(fsp)));
7277 close_file(req, fsp, NORMAL_CLOSE);
7278 return NT_STATUS_INVALID_PARAMETER;
7282 * See if others still have the file open. If this is the case, then
7283 * don't delete. If all opens are POSIX delete we can set the delete
7284 * on close disposition.
7286 for (i=0; i<lck->num_share_modes; i++) {
7287 struct share_mode_entry *e = &lck->share_modes[i];
7288 if (is_valid_share_mode_entry(e)) {
7289 if (e->flags & SHARE_MODE_FLAG_POSIX_OPEN) {
7290 continue;
7292 /* Fail with sharing violation. */
7293 close_file(req, fsp, NORMAL_CLOSE);
7294 TALLOC_FREE(lck);
7295 return NT_STATUS_SHARING_VIOLATION;
7300 * Set the delete on close.
7302 status = smb_set_file_disposition_info(conn,
7303 &del,
7305 fsp,
7306 smb_fname);
7308 if (!NT_STATUS_IS_OK(status)) {
7309 close_file(req, fsp, NORMAL_CLOSE);
7310 TALLOC_FREE(lck);
7311 return status;
7313 TALLOC_FREE(lck);
7314 return close_file(req, fsp, NORMAL_CLOSE);
7317 NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
7318 struct smb_request *req,
7319 TALLOC_CTX *mem_ctx,
7320 uint16_t info_level,
7321 files_struct *fsp,
7322 struct smb_filename *smb_fname,
7323 char **ppdata, int total_data,
7324 int *ret_data_size)
7326 char *pdata = *ppdata;
7327 NTSTATUS status = NT_STATUS_OK;
7328 int data_return_size = 0;
7330 *ret_data_size = 0;
7332 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
7333 return NT_STATUS_INVALID_LEVEL;
7336 if (!CAN_WRITE(conn)) {
7337 /* Allow POSIX opens. The open path will deny
7338 * any non-readonly opens. */
7339 if (info_level != SMB_POSIX_PATH_OPEN) {
7340 return NT_STATUS_DOS(ERRSRV, ERRaccess);
7344 DEBUG(3,("smbd_do_setfilepathinfo: %s (fnum %d) info_level=%d "
7345 "totdata=%d\n", smb_fname_str_dbg(smb_fname),
7346 fsp ? fsp->fnum : -1, info_level, total_data));
7348 switch (info_level) {
7350 case SMB_INFO_STANDARD:
7352 status = smb_set_info_standard(conn,
7353 pdata,
7354 total_data,
7355 fsp,
7356 smb_fname);
7357 break;
7360 case SMB_INFO_SET_EA:
7362 status = smb_info_set_ea(conn,
7363 pdata,
7364 total_data,
7365 fsp,
7366 smb_fname);
7367 break;
7370 case SMB_SET_FILE_BASIC_INFO:
7371 case SMB_FILE_BASIC_INFORMATION:
7373 status = smb_set_file_basic_info(conn,
7374 pdata,
7375 total_data,
7376 fsp,
7377 smb_fname);
7378 break;
7381 case SMB_FILE_ALLOCATION_INFORMATION:
7382 case SMB_SET_FILE_ALLOCATION_INFO:
7384 status = smb_set_file_allocation_info(conn, req,
7385 pdata,
7386 total_data,
7387 fsp,
7388 smb_fname);
7389 break;
7392 case SMB_FILE_END_OF_FILE_INFORMATION:
7393 case SMB_SET_FILE_END_OF_FILE_INFO:
7396 * XP/Win7 both fail after the createfile with
7397 * SMB_SET_FILE_END_OF_FILE_INFO but not
7398 * SMB_FILE_END_OF_FILE_INFORMATION (pass-through).
7399 * The level is known here, so pass it down
7400 * appropriately.
7402 bool should_fail =
7403 (info_level == SMB_SET_FILE_END_OF_FILE_INFO);
7405 status = smb_set_file_end_of_file_info(conn, req,
7406 pdata,
7407 total_data,
7408 fsp,
7409 smb_fname,
7410 should_fail);
7411 break;
7414 case SMB_FILE_DISPOSITION_INFORMATION:
7415 case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
7417 #if 0
7418 /* JRA - We used to just ignore this on a path ?
7419 * Shouldn't this be invalid level on a pathname
7420 * based call ?
7422 if (tran_call != TRANSACT2_SETFILEINFO) {
7423 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
7425 #endif
7426 status = smb_set_file_disposition_info(conn,
7427 pdata,
7428 total_data,
7429 fsp,
7430 smb_fname);
7431 break;
7434 case SMB_FILE_POSITION_INFORMATION:
7436 status = smb_file_position_information(conn,
7437 pdata,
7438 total_data,
7439 fsp);
7440 break;
7443 case SMB_FILE_FULL_EA_INFORMATION:
7445 status = smb_set_file_full_ea_info(conn,
7446 pdata,
7447 total_data,
7448 fsp);
7449 break;
7452 /* From tridge Samba4 :
7453 * MODE_INFORMATION in setfileinfo (I have no
7454 * idea what "mode information" on a file is - it takes a value of 0,
7455 * 2, 4 or 6. What could it be?).
7458 case SMB_FILE_MODE_INFORMATION:
7460 status = smb_file_mode_information(conn,
7461 pdata,
7462 total_data);
7463 break;
7467 * CIFS UNIX extensions.
7470 case SMB_SET_FILE_UNIX_BASIC:
7472 status = smb_set_file_unix_basic(conn, req,
7473 pdata,
7474 total_data,
7475 fsp,
7476 smb_fname);
7477 break;
7480 case SMB_SET_FILE_UNIX_INFO2:
7482 status = smb_set_file_unix_info2(conn, req,
7483 pdata,
7484 total_data,
7485 fsp,
7486 smb_fname);
7487 break;
7490 case SMB_SET_FILE_UNIX_LINK:
7492 if (fsp) {
7493 /* We must have a pathname for this. */
7494 return NT_STATUS_INVALID_LEVEL;
7496 status = smb_set_file_unix_link(conn, req, pdata,
7497 total_data, smb_fname);
7498 break;
7501 case SMB_SET_FILE_UNIX_HLINK:
7503 if (fsp) {
7504 /* We must have a pathname for this. */
7505 return NT_STATUS_INVALID_LEVEL;
7507 status = smb_set_file_unix_hlink(conn, req,
7508 pdata, total_data,
7509 smb_fname);
7510 break;
7513 case SMB_FILE_RENAME_INFORMATION:
7515 status = smb_file_rename_information(conn, req,
7516 pdata, total_data,
7517 fsp, smb_fname);
7518 break;
7521 #if defined(HAVE_POSIX_ACLS)
7522 case SMB_SET_POSIX_ACL:
7524 status = smb_set_posix_acl(conn,
7525 pdata,
7526 total_data,
7527 fsp,
7528 smb_fname);
7529 break;
7531 #endif
7533 case SMB_SET_POSIX_LOCK:
7535 if (!fsp) {
7536 return NT_STATUS_INVALID_LEVEL;
7538 status = smb_set_posix_lock(conn, req,
7539 pdata, total_data, fsp);
7540 break;
7543 case SMB_POSIX_PATH_OPEN:
7545 if (fsp) {
7546 /* We must have a pathname for this. */
7547 return NT_STATUS_INVALID_LEVEL;
7550 status = smb_posix_open(conn, req,
7551 ppdata,
7552 total_data,
7553 smb_fname,
7554 &data_return_size);
7555 break;
7558 case SMB_POSIX_PATH_UNLINK:
7560 if (fsp) {
7561 /* We must have a pathname for this. */
7562 return NT_STATUS_INVALID_LEVEL;
7565 status = smb_posix_unlink(conn, req,
7566 pdata,
7567 total_data,
7568 smb_fname);
7569 break;
7572 default:
7573 return NT_STATUS_INVALID_LEVEL;
7576 if (!NT_STATUS_IS_OK(status)) {
7577 return status;
7580 *ret_data_size = data_return_size;
7581 return NT_STATUS_OK;
7584 /****************************************************************************
7585 Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname).
7586 ****************************************************************************/
7588 static void call_trans2setfilepathinfo(connection_struct *conn,
7589 struct smb_request *req,
7590 unsigned int tran_call,
7591 char **pparams, int total_params,
7592 char **ppdata, int total_data,
7593 unsigned int max_data_bytes)
7595 char *params = *pparams;
7596 char *pdata = *ppdata;
7597 uint16 info_level;
7598 struct smb_filename *smb_fname = NULL;
7599 files_struct *fsp = NULL;
7600 NTSTATUS status = NT_STATUS_OK;
7601 int data_return_size = 0;
7603 if (!params) {
7604 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7605 return;
7608 if (tran_call == TRANSACT2_SETFILEINFO) {
7609 if (total_params < 4) {
7610 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7611 return;
7614 fsp = file_fsp(req, SVAL(params,0));
7615 /* Basic check for non-null fsp. */
7616 if (!check_fsp_open(conn, req, fsp)) {
7617 return;
7619 info_level = SVAL(params,2);
7621 status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
7622 &smb_fname);
7623 if (!NT_STATUS_IS_OK(status)) {
7624 reply_nterror(req, status);
7625 return;
7628 if(fsp->is_directory || fsp->fh->fd == -1) {
7630 * This is actually a SETFILEINFO on a directory
7631 * handle (returned from an NT SMB). NT5.0 seems
7632 * to do this call. JRA.
7634 if (INFO_LEVEL_IS_UNIX(info_level)) {
7635 /* Always do lstat for UNIX calls. */
7636 if (SMB_VFS_LSTAT(conn, smb_fname)) {
7637 DEBUG(3,("call_trans2setfilepathinfo: "
7638 "SMB_VFS_LSTAT of %s failed "
7639 "(%s)\n",
7640 smb_fname_str_dbg(smb_fname),
7641 strerror(errno)));
7642 reply_nterror(req, map_nt_error_from_unix(errno));
7643 return;
7645 } else {
7646 if (SMB_VFS_STAT(conn, smb_fname) != 0) {
7647 DEBUG(3,("call_trans2setfilepathinfo: "
7648 "fileinfo of %s failed (%s)\n",
7649 smb_fname_str_dbg(smb_fname),
7650 strerror(errno)));
7651 reply_nterror(req, map_nt_error_from_unix(errno));
7652 return;
7655 } else if (fsp->print_file) {
7657 * Doing a DELETE_ON_CLOSE should cancel a print job.
7659 if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
7660 fsp->fh->private_options |= FILE_DELETE_ON_CLOSE;
7662 DEBUG(3,("call_trans2setfilepathinfo: "
7663 "Cancelling print job (%s)\n",
7664 fsp_str_dbg(fsp)));
7666 SSVAL(params,0,0);
7667 send_trans2_replies(conn, req, params, 2,
7668 *ppdata, 0,
7669 max_data_bytes);
7670 return;
7671 } else {
7672 reply_doserror(req, ERRDOS, ERRbadpath);
7673 return;
7675 } else {
7677 * Original code - this is an open file.
7679 if (!check_fsp(conn, req, fsp)) {
7680 return;
7683 if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
7684 DEBUG(3,("call_trans2setfilepathinfo: fstat "
7685 "of fnum %d failed (%s)\n", fsp->fnum,
7686 strerror(errno)));
7687 reply_nterror(req, map_nt_error_from_unix(errno));
7688 return;
7691 } else {
7692 char *fname = NULL;
7694 /* set path info */
7695 if (total_params < 7) {
7696 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7697 return;
7700 info_level = SVAL(params,0);
7701 srvstr_get_path(req, params, req->flags2, &fname, &params[6],
7702 total_params - 6, STR_TERMINATE,
7703 &status);
7704 if (!NT_STATUS_IS_OK(status)) {
7705 reply_nterror(req, status);
7706 return;
7709 status = filename_convert(req, conn,
7710 req->flags2 & FLAGS2_DFS_PATHNAMES,
7711 fname,
7713 NULL,
7714 &smb_fname);
7715 if (!NT_STATUS_IS_OK(status)) {
7716 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7717 reply_botherror(req,
7718 NT_STATUS_PATH_NOT_COVERED,
7719 ERRSRV, ERRbadpath);
7720 return;
7722 reply_nterror(req, status);
7723 return;
7726 if (INFO_LEVEL_IS_UNIX(info_level)) {
7728 * For CIFS UNIX extensions the target name may not exist.
7731 /* Always do lstat for UNIX calls. */
7732 SMB_VFS_LSTAT(conn, smb_fname);
7734 } else if (!VALID_STAT(smb_fname->st) &&
7735 SMB_VFS_STAT(conn, smb_fname)) {
7736 DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of "
7737 "%s failed (%s)\n",
7738 smb_fname_str_dbg(smb_fname),
7739 strerror(errno)));
7740 reply_nterror(req, map_nt_error_from_unix(errno));
7741 return;
7745 DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d "
7746 "totdata=%d\n", tran_call, smb_fname_str_dbg(smb_fname),
7747 fsp ? fsp->fnum : -1, info_level,total_data));
7749 /* Realloc the parameter size */
7750 *pparams = (char *)SMB_REALLOC(*pparams,2);
7751 if (*pparams == NULL) {
7752 reply_nterror(req, NT_STATUS_NO_MEMORY);
7753 return;
7755 params = *pparams;
7757 SSVAL(params,0,0);
7759 status = smbd_do_setfilepathinfo(conn, req, req,
7760 info_level,
7761 fsp,
7762 smb_fname,
7763 ppdata, total_data,
7764 &data_return_size);
7765 if (!NT_STATUS_IS_OK(status)) {
7766 if (open_was_deferred(req->mid)) {
7767 /* We have re-scheduled this call. */
7768 return;
7770 if (blocking_lock_was_deferred(req->mid)) {
7771 /* We have re-scheduled this call. */
7772 return;
7774 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7775 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7776 ERRSRV, ERRbadpath);
7777 return;
7779 if (info_level == SMB_POSIX_PATH_OPEN) {
7780 reply_openerror(req, status);
7781 return;
7784 reply_nterror(req, status);
7785 return;
7788 send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size,
7789 max_data_bytes);
7791 return;
7794 /****************************************************************************
7795 Reply to a TRANS2_MKDIR (make directory with extended attributes).
7796 ****************************************************************************/
7798 static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
7799 char **pparams, int total_params,
7800 char **ppdata, int total_data,
7801 unsigned int max_data_bytes)
7803 struct smb_filename *smb_dname = NULL;
7804 char *params = *pparams;
7805 char *pdata = *ppdata;
7806 char *directory = NULL;
7807 NTSTATUS status = NT_STATUS_OK;
7808 struct ea_list *ea_list = NULL;
7809 TALLOC_CTX *ctx = talloc_tos();
7811 if (!CAN_WRITE(conn)) {
7812 reply_doserror(req, ERRSRV, ERRaccess);
7813 return;
7816 if (total_params < 5) {
7817 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7818 return;
7821 srvstr_get_path(ctx, params, req->flags2, &directory, &params[4],
7822 total_params - 4, STR_TERMINATE,
7823 &status);
7824 if (!NT_STATUS_IS_OK(status)) {
7825 reply_nterror(req, status);
7826 return;
7829 DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
7831 status = filename_convert(ctx,
7832 conn,
7833 req->flags2 & FLAGS2_DFS_PATHNAMES,
7834 directory,
7836 NULL,
7837 &smb_dname);
7839 if (!NT_STATUS_IS_OK(status)) {
7840 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7841 reply_botherror(req,
7842 NT_STATUS_PATH_NOT_COVERED,
7843 ERRSRV, ERRbadpath);
7844 return;
7846 reply_nterror(req, status);
7847 return;
7850 /* Any data in this call is an EA list. */
7851 if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
7852 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
7853 goto out;
7857 * OS/2 workplace shell seems to send SET_EA requests of "null"
7858 * length (4 bytes containing IVAL 4).
7859 * They seem to have no effect. Bug #3212. JRA.
7862 if (total_data != 4) {
7863 if (total_data < 10) {
7864 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7865 goto out;
7868 if (IVAL(pdata,0) > total_data) {
7869 DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
7870 IVAL(pdata,0), (unsigned int)total_data));
7871 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7872 goto out;
7875 ea_list = read_ea_list(talloc_tos(), pdata + 4,
7876 total_data - 4);
7877 if (!ea_list) {
7878 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7879 goto out;
7882 /* If total_data == 4 Windows doesn't care what values
7883 * are placed in that field, it just ignores them.
7884 * The System i QNTC IBM SMB client puts bad values here,
7885 * so ignore them. */
7887 status = create_directory(conn, req, smb_dname);
7889 if (!NT_STATUS_IS_OK(status)) {
7890 reply_nterror(req, status);
7891 goto out;
7894 /* Try and set any given EA. */
7895 if (ea_list) {
7896 status = set_ea(conn, NULL, smb_dname, ea_list);
7897 if (!NT_STATUS_IS_OK(status)) {
7898 reply_nterror(req, status);
7899 goto out;
7903 /* Realloc the parameter and data sizes */
7904 *pparams = (char *)SMB_REALLOC(*pparams,2);
7905 if(*pparams == NULL) {
7906 reply_nterror(req, NT_STATUS_NO_MEMORY);
7907 goto out;
7909 params = *pparams;
7911 SSVAL(params,0,0);
7913 send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes);
7915 out:
7916 TALLOC_FREE(smb_dname);
7917 return;
7920 /****************************************************************************
7921 Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
7922 We don't actually do this - we just send a null response.
7923 ****************************************************************************/
7925 static void call_trans2findnotifyfirst(connection_struct *conn,
7926 struct smb_request *req,
7927 char **pparams, int total_params,
7928 char **ppdata, int total_data,
7929 unsigned int max_data_bytes)
7931 char *params = *pparams;
7932 uint16 info_level;
7934 if (total_params < 6) {
7935 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7936 return;
7939 info_level = SVAL(params,4);
7940 DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
7942 switch (info_level) {
7943 case 1:
7944 case 2:
7945 break;
7946 default:
7947 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
7948 return;
7951 /* Realloc the parameter and data sizes */
7952 *pparams = (char *)SMB_REALLOC(*pparams,6);
7953 if (*pparams == NULL) {
7954 reply_nterror(req, NT_STATUS_NO_MEMORY);
7955 return;
7957 params = *pparams;
7959 SSVAL(params,0,fnf_handle);
7960 SSVAL(params,2,0); /* No changes */
7961 SSVAL(params,4,0); /* No EA errors */
7963 fnf_handle++;
7965 if(fnf_handle == 0)
7966 fnf_handle = 257;
7968 send_trans2_replies(conn, req, params, 6, *ppdata, 0, max_data_bytes);
7970 return;
7973 /****************************************************************************
7974 Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
7975 changes). Currently this does nothing.
7976 ****************************************************************************/
7978 static void call_trans2findnotifynext(connection_struct *conn,
7979 struct smb_request *req,
7980 char **pparams, int total_params,
7981 char **ppdata, int total_data,
7982 unsigned int max_data_bytes)
7984 char *params = *pparams;
7986 DEBUG(3,("call_trans2findnotifynext\n"));
7988 /* Realloc the parameter and data sizes */
7989 *pparams = (char *)SMB_REALLOC(*pparams,4);
7990 if (*pparams == NULL) {
7991 reply_nterror(req, NT_STATUS_NO_MEMORY);
7992 return;
7994 params = *pparams;
7996 SSVAL(params,0,0); /* No changes */
7997 SSVAL(params,2,0); /* No EA errors */
7999 send_trans2_replies(conn, req, params, 4, *ppdata, 0, max_data_bytes);
8001 return;
8004 /****************************************************************************
8005 Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
8006 ****************************************************************************/
8008 static void call_trans2getdfsreferral(connection_struct *conn,
8009 struct smb_request *req,
8010 char **pparams, int total_params,
8011 char **ppdata, int total_data,
8012 unsigned int max_data_bytes)
8014 char *params = *pparams;
8015 char *pathname = NULL;
8016 int reply_size = 0;
8017 int max_referral_level;
8018 NTSTATUS status = NT_STATUS_OK;
8019 TALLOC_CTX *ctx = talloc_tos();
8021 DEBUG(10,("call_trans2getdfsreferral\n"));
8023 if (total_params < 3) {
8024 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8025 return;
8028 max_referral_level = SVAL(params,0);
8030 if(!lp_host_msdfs()) {
8031 reply_doserror(req, ERRDOS, ERRbadfunc);
8032 return;
8035 srvstr_pull_talloc(ctx, params, req->flags2, &pathname, &params[2],
8036 total_params - 2, STR_TERMINATE);
8037 if (!pathname) {
8038 reply_nterror(req, NT_STATUS_NOT_FOUND);
8039 return;
8041 if((reply_size = setup_dfs_referral(conn, pathname, max_referral_level,
8042 ppdata,&status)) < 0) {
8043 reply_nterror(req, status);
8044 return;
8047 SSVAL(req->inbuf, smb_flg2,
8048 SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
8049 send_trans2_replies(conn, req,0,0,*ppdata,reply_size, max_data_bytes);
8051 return;
8054 #define LMCAT_SPL 0x53
8055 #define LMFUNC_GETJOBID 0x60
8057 /****************************************************************************
8058 Reply to a TRANS2_IOCTL - used for OS/2 printing.
8059 ****************************************************************************/
8061 static void call_trans2ioctl(connection_struct *conn,
8062 struct smb_request *req,
8063 char **pparams, int total_params,
8064 char **ppdata, int total_data,
8065 unsigned int max_data_bytes)
8067 char *pdata = *ppdata;
8068 files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
8070 /* check for an invalid fid before proceeding */
8072 if (!fsp) {
8073 reply_doserror(req, ERRDOS, ERRbadfid);
8074 return;
8077 if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
8078 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
8079 *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
8080 if (*ppdata == NULL) {
8081 reply_nterror(req, NT_STATUS_NO_MEMORY);
8082 return;
8084 pdata = *ppdata;
8086 /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
8087 CAN ACCEPT THIS IN UNICODE. JRA. */
8089 SSVAL(pdata,0,fsp->rap_print_jobid); /* Job number */
8090 srvstr_push(pdata, req->flags2, pdata + 2,
8091 global_myname(), 15,
8092 STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */
8093 srvstr_push(pdata, req->flags2, pdata+18,
8094 lp_servicename(SNUM(conn)), 13,
8095 STR_ASCII|STR_TERMINATE); /* Service name */
8096 send_trans2_replies(conn, req, *pparams, 0, *ppdata, 32,
8097 max_data_bytes);
8098 return;
8101 DEBUG(2,("Unknown TRANS2_IOCTL\n"));
8102 reply_doserror(req, ERRSRV, ERRerror);
8105 /****************************************************************************
8106 Reply to a SMBfindclose (stop trans2 directory search).
8107 ****************************************************************************/
8109 void reply_findclose(struct smb_request *req)
8111 int dptr_num;
8112 struct smbd_server_connection *sconn = smbd_server_conn;
8114 START_PROFILE(SMBfindclose);
8116 if (req->wct < 1) {
8117 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8118 END_PROFILE(SMBfindclose);
8119 return;
8122 dptr_num = SVALS(req->vwv+0, 0);
8124 DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
8126 dptr_close(sconn, &dptr_num);
8128 reply_outbuf(req, 0, 0);
8130 DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));
8132 END_PROFILE(SMBfindclose);
8133 return;
8136 /****************************************************************************
8137 Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search).
8138 ****************************************************************************/
8140 void reply_findnclose(struct smb_request *req)
8142 int dptr_num;
8144 START_PROFILE(SMBfindnclose);
8146 if (req->wct < 1) {
8147 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8148 END_PROFILE(SMBfindnclose);
8149 return;
8152 dptr_num = SVAL(req->vwv+0, 0);
8154 DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num));
8156 /* We never give out valid handles for a
8157 findnotifyfirst - so any dptr_num is ok here.
8158 Just ignore it. */
8160 reply_outbuf(req, 0, 0);
8162 DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));
8164 END_PROFILE(SMBfindnclose);
8165 return;
8168 static void handle_trans2(connection_struct *conn, struct smb_request *req,
8169 struct trans_state *state)
8171 if (get_Protocol() >= PROTOCOL_NT1) {
8172 req->flags2 |= 0x40; /* IS_LONG_NAME */
8173 SSVAL(req->inbuf,smb_flg2,req->flags2);
8176 if (conn->encrypt_level == Required && !req->encrypted) {
8177 if (state->call != TRANSACT2_QFSINFO &&
8178 state->call != TRANSACT2_SETFSINFO) {
8179 DEBUG(0,("handle_trans2: encryption required "
8180 "with call 0x%x\n",
8181 (unsigned int)state->call));
8182 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8183 return;
8187 SMB_PERFCOUNT_SET_SUBOP(&req->pcd, state->call);
8189 /* Now we must call the relevant TRANS2 function */
8190 switch(state->call) {
8191 case TRANSACT2_OPEN:
8193 START_PROFILE(Trans2_open);
8194 call_trans2open(conn, req,
8195 &state->param, state->total_param,
8196 &state->data, state->total_data,
8197 state->max_data_return);
8198 END_PROFILE(Trans2_open);
8199 break;
8202 case TRANSACT2_FINDFIRST:
8204 START_PROFILE(Trans2_findfirst);
8205 call_trans2findfirst(conn, req,
8206 &state->param, state->total_param,
8207 &state->data, state->total_data,
8208 state->max_data_return);
8209 END_PROFILE(Trans2_findfirst);
8210 break;
8213 case TRANSACT2_FINDNEXT:
8215 START_PROFILE(Trans2_findnext);
8216 call_trans2findnext(conn, req,
8217 &state->param, state->total_param,
8218 &state->data, state->total_data,
8219 state->max_data_return);
8220 END_PROFILE(Trans2_findnext);
8221 break;
8224 case TRANSACT2_QFSINFO:
8226 START_PROFILE(Trans2_qfsinfo);
8227 call_trans2qfsinfo(conn, req,
8228 &state->param, state->total_param,
8229 &state->data, state->total_data,
8230 state->max_data_return);
8231 END_PROFILE(Trans2_qfsinfo);
8232 break;
8235 case TRANSACT2_SETFSINFO:
8237 START_PROFILE(Trans2_setfsinfo);
8238 call_trans2setfsinfo(conn, req,
8239 &state->param, state->total_param,
8240 &state->data, state->total_data,
8241 state->max_data_return);
8242 END_PROFILE(Trans2_setfsinfo);
8243 break;
8246 case TRANSACT2_QPATHINFO:
8247 case TRANSACT2_QFILEINFO:
8249 START_PROFILE(Trans2_qpathinfo);
8250 call_trans2qfilepathinfo(conn, req, state->call,
8251 &state->param, state->total_param,
8252 &state->data, state->total_data,
8253 state->max_data_return);
8254 END_PROFILE(Trans2_qpathinfo);
8255 break;
8258 case TRANSACT2_SETPATHINFO:
8259 case TRANSACT2_SETFILEINFO:
8261 START_PROFILE(Trans2_setpathinfo);
8262 call_trans2setfilepathinfo(conn, req, state->call,
8263 &state->param, state->total_param,
8264 &state->data, state->total_data,
8265 state->max_data_return);
8266 END_PROFILE(Trans2_setpathinfo);
8267 break;
8270 case TRANSACT2_FINDNOTIFYFIRST:
8272 START_PROFILE(Trans2_findnotifyfirst);
8273 call_trans2findnotifyfirst(conn, req,
8274 &state->param, state->total_param,
8275 &state->data, state->total_data,
8276 state->max_data_return);
8277 END_PROFILE(Trans2_findnotifyfirst);
8278 break;
8281 case TRANSACT2_FINDNOTIFYNEXT:
8283 START_PROFILE(Trans2_findnotifynext);
8284 call_trans2findnotifynext(conn, req,
8285 &state->param, state->total_param,
8286 &state->data, state->total_data,
8287 state->max_data_return);
8288 END_PROFILE(Trans2_findnotifynext);
8289 break;
8292 case TRANSACT2_MKDIR:
8294 START_PROFILE(Trans2_mkdir);
8295 call_trans2mkdir(conn, req,
8296 &state->param, state->total_param,
8297 &state->data, state->total_data,
8298 state->max_data_return);
8299 END_PROFILE(Trans2_mkdir);
8300 break;
8303 case TRANSACT2_GET_DFS_REFERRAL:
8305 START_PROFILE(Trans2_get_dfs_referral);
8306 call_trans2getdfsreferral(conn, req,
8307 &state->param, state->total_param,
8308 &state->data, state->total_data,
8309 state->max_data_return);
8310 END_PROFILE(Trans2_get_dfs_referral);
8311 break;
8314 case TRANSACT2_IOCTL:
8316 START_PROFILE(Trans2_ioctl);
8317 call_trans2ioctl(conn, req,
8318 &state->param, state->total_param,
8319 &state->data, state->total_data,
8320 state->max_data_return);
8321 END_PROFILE(Trans2_ioctl);
8322 break;
8325 default:
8326 /* Error in request */
8327 DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
8328 reply_doserror(req, ERRSRV,ERRerror);
8332 /****************************************************************************
8333 Reply to a SMBtrans2.
8334 ****************************************************************************/
8336 void reply_trans2(struct smb_request *req)
8338 connection_struct *conn = req->conn;
8339 unsigned int dsoff;
8340 unsigned int dscnt;
8341 unsigned int psoff;
8342 unsigned int pscnt;
8343 unsigned int tran_call;
8344 struct trans_state *state;
8345 NTSTATUS result;
8347 START_PROFILE(SMBtrans2);
8349 if (req->wct < 14) {
8350 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8351 END_PROFILE(SMBtrans2);
8352 return;
8355 dsoff = SVAL(req->vwv+12, 0);
8356 dscnt = SVAL(req->vwv+11, 0);
8357 psoff = SVAL(req->vwv+10, 0);
8358 pscnt = SVAL(req->vwv+9, 0);
8359 tran_call = SVAL(req->vwv+14, 0);
8361 result = allow_new_trans(conn->pending_trans, req->mid);
8362 if (!NT_STATUS_IS_OK(result)) {
8363 DEBUG(2, ("Got invalid trans2 request: %s\n",
8364 nt_errstr(result)));
8365 reply_nterror(req, result);
8366 END_PROFILE(SMBtrans2);
8367 return;
8370 if (IS_IPC(conn)) {
8371 switch (tran_call) {
8372 /* List the allowed trans2 calls on IPC$ */
8373 case TRANSACT2_OPEN:
8374 case TRANSACT2_GET_DFS_REFERRAL:
8375 case TRANSACT2_QFILEINFO:
8376 case TRANSACT2_QFSINFO:
8377 case TRANSACT2_SETFSINFO:
8378 break;
8379 default:
8380 reply_doserror(req, ERRSRV, ERRaccess);
8381 END_PROFILE(SMBtrans2);
8382 return;
8386 if ((state = TALLOC_P(conn, struct trans_state)) == NULL) {
8387 DEBUG(0, ("talloc failed\n"));
8388 reply_nterror(req, NT_STATUS_NO_MEMORY);
8389 END_PROFILE(SMBtrans2);
8390 return;
8393 state->cmd = SMBtrans2;
8395 state->mid = req->mid;
8396 state->vuid = req->vuid;
8397 state->setup_count = SVAL(req->vwv+13, 0);
8398 state->setup = NULL;
8399 state->total_param = SVAL(req->vwv+0, 0);
8400 state->param = NULL;
8401 state->total_data = SVAL(req->vwv+1, 0);
8402 state->data = NULL;
8403 state->max_param_return = SVAL(req->vwv+2, 0);
8404 state->max_data_return = SVAL(req->vwv+3, 0);
8405 state->max_setup_return = SVAL(req->vwv+4, 0);
8406 state->close_on_completion = BITSETW(req->vwv+5, 0);
8407 state->one_way = BITSETW(req->vwv+5, 1);
8409 state->call = tran_call;
8411 /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
8412 is so as a sanity check */
8413 if (state->setup_count != 1) {
8415 * Need to have rc=0 for ioctl to get job id for OS/2.
8416 * Network printing will fail if function is not successful.
8417 * Similar function in reply.c will be used if protocol
8418 * is LANMAN1.0 instead of LM1.2X002.
8419 * Until DosPrintSetJobInfo with PRJINFO3 is supported,
8420 * outbuf doesn't have to be set(only job id is used).
8422 if ( (state->setup_count == 4)
8423 && (tran_call == TRANSACT2_IOCTL)
8424 && (SVAL(req->vwv+16, 0) == LMCAT_SPL)
8425 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
8426 DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
8427 } else {
8428 DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
8429 DEBUG(2,("Transaction is %d\n",tran_call));
8430 TALLOC_FREE(state);
8431 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8432 END_PROFILE(SMBtrans2);
8433 return;
8437 if ((dscnt > state->total_data) || (pscnt > state->total_param))
8438 goto bad_param;
8440 if (state->total_data) {
8442 if (trans_oob(state->total_data, 0, dscnt)
8443 || trans_oob(smb_len(req->inbuf), dsoff, dscnt)) {
8444 goto bad_param;
8447 /* Can't use talloc here, the core routines do realloc on the
8448 * params and data. */
8449 state->data = (char *)SMB_MALLOC(state->total_data);
8450 if (state->data == NULL) {
8451 DEBUG(0,("reply_trans2: data malloc fail for %u "
8452 "bytes !\n", (unsigned int)state->total_data));
8453 TALLOC_FREE(state);
8454 reply_nterror(req, NT_STATUS_NO_MEMORY);
8455 END_PROFILE(SMBtrans2);
8456 return;
8459 memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
8462 if (state->total_param) {
8464 if (trans_oob(state->total_param, 0, pscnt)
8465 || trans_oob(smb_len(req->inbuf), psoff, pscnt)) {
8466 goto bad_param;
8469 /* Can't use talloc here, the core routines do realloc on the
8470 * params and data. */
8471 state->param = (char *)SMB_MALLOC(state->total_param);
8472 if (state->param == NULL) {
8473 DEBUG(0,("reply_trans: param malloc fail for %u "
8474 "bytes !\n", (unsigned int)state->total_param));
8475 SAFE_FREE(state->data);
8476 TALLOC_FREE(state);
8477 reply_nterror(req, NT_STATUS_NO_MEMORY);
8478 END_PROFILE(SMBtrans2);
8479 return;
8482 memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
8485 state->received_data = dscnt;
8486 state->received_param = pscnt;
8488 if ((state->received_param == state->total_param) &&
8489 (state->received_data == state->total_data)) {
8491 handle_trans2(conn, req, state);
8493 SAFE_FREE(state->data);
8494 SAFE_FREE(state->param);
8495 TALLOC_FREE(state);
8496 END_PROFILE(SMBtrans2);
8497 return;
8500 DLIST_ADD(conn->pending_trans, state);
8502 /* We need to send an interim response then receive the rest
8503 of the parameter/data bytes */
8504 reply_outbuf(req, 0, 0);
8505 show_msg((char *)req->outbuf);
8506 END_PROFILE(SMBtrans2);
8507 return;
8509 bad_param:
8511 DEBUG(0,("reply_trans2: invalid trans parameters\n"));
8512 SAFE_FREE(state->data);
8513 SAFE_FREE(state->param);
8514 TALLOC_FREE(state);
8515 END_PROFILE(SMBtrans2);
8516 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8520 /****************************************************************************
8521 Reply to a SMBtranss2
8522 ****************************************************************************/
8524 void reply_transs2(struct smb_request *req)
8526 connection_struct *conn = req->conn;
8527 unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
8528 struct trans_state *state;
8530 START_PROFILE(SMBtranss2);
8532 show_msg((char *)req->inbuf);
8534 if (req->wct < 8) {
8535 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8536 END_PROFILE(SMBtranss2);
8537 return;
8540 for (state = conn->pending_trans; state != NULL;
8541 state = state->next) {
8542 if (state->mid == req->mid) {
8543 break;
8547 if ((state == NULL) || (state->cmd != SMBtrans2)) {
8548 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8549 END_PROFILE(SMBtranss2);
8550 return;
8553 /* Revise state->total_param and state->total_data in case they have
8554 changed downwards */
8556 if (SVAL(req->vwv+0, 0) < state->total_param)
8557 state->total_param = SVAL(req->vwv+0, 0);
8558 if (SVAL(req->vwv+1, 0) < state->total_data)
8559 state->total_data = SVAL(req->vwv+1, 0);
8561 pcnt = SVAL(req->vwv+2, 0);
8562 poff = SVAL(req->vwv+3, 0);
8563 pdisp = SVAL(req->vwv+4, 0);
8565 dcnt = SVAL(req->vwv+5, 0);
8566 doff = SVAL(req->vwv+6, 0);
8567 ddisp = SVAL(req->vwv+7, 0);
8569 state->received_param += pcnt;
8570 state->received_data += dcnt;
8572 if ((state->received_data > state->total_data) ||
8573 (state->received_param > state->total_param))
8574 goto bad_param;
8576 if (pcnt) {
8577 if (trans_oob(state->total_param, pdisp, pcnt)
8578 || trans_oob(smb_len(req->inbuf), poff, pcnt)) {
8579 goto bad_param;
8581 memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
8584 if (dcnt) {
8585 if (trans_oob(state->total_data, ddisp, dcnt)
8586 || trans_oob(smb_len(req->inbuf), doff, dcnt)) {
8587 goto bad_param;
8589 memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
8592 if ((state->received_param < state->total_param) ||
8593 (state->received_data < state->total_data)) {
8594 END_PROFILE(SMBtranss2);
8595 return;
8598 handle_trans2(conn, req, state);
8600 DLIST_REMOVE(conn->pending_trans, state);
8601 SAFE_FREE(state->data);
8602 SAFE_FREE(state->param);
8603 TALLOC_FREE(state);
8605 END_PROFILE(SMBtranss2);
8606 return;
8608 bad_param:
8610 DEBUG(0,("reply_transs2: invalid trans parameters\n"));
8611 DLIST_REMOVE(conn->pending_trans, state);
8612 SAFE_FREE(state->data);
8613 SAFE_FREE(state->param);
8614 TALLOC_FREE(state);
8615 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8616 END_PROFILE(SMBtranss2);
8617 return;