Start fixing the RAW-STREAMS test - ensure that the xattr
[Samba/fernandojvsilva.git] / source3 / smbd / trans2.c
blob59b778cf45c74da4cd6a71588e94d6826cd0a4da
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 extern enum protocol_types Protocol;
33 #define DIR_ENTRY_SAFETY_MARGIN 4096
35 static char *store_file_unix_basic(connection_struct *conn,
36 char *pdata,
37 files_struct *fsp,
38 const SMB_STRUCT_STAT *psbuf);
40 static char *store_file_unix_basic_info2(connection_struct *conn,
41 char *pdata,
42 files_struct *fsp,
43 const SMB_STRUCT_STAT *psbuf);
45 /********************************************************************
46 Roundup a value to the nearest allocation roundup size boundary.
47 Only do this for Windows clients.
48 ********************************************************************/
50 uint64_t smb_roundup(connection_struct *conn, uint64_t val)
52 uint64_t rval = lp_allocation_roundup_size(SNUM(conn));
54 /* Only roundup for Windows clients. */
55 enum remote_arch_types ra_type = get_remote_arch();
56 if (rval && (ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
57 val = SMB_ROUNDUP(val,rval);
59 return val;
62 /****************************************************************************
63 Utility functions for dealing with extended attributes.
64 ****************************************************************************/
66 /****************************************************************************
67 Refuse to allow clients to overwrite our private xattrs.
68 ****************************************************************************/
70 static bool samba_private_attr_name(const char *unix_ea_name)
72 static const char * const prohibited_ea_names[] = {
73 SAMBA_POSIX_INHERITANCE_EA_NAME,
74 SAMBA_XATTR_DOS_ATTRIB,
75 SAMBA_XATTR_DOSTIMESTAMPS,
76 SAMBA_XATTR_MARKER,
77 NULL
80 int i;
82 for (i = 0; prohibited_ea_names[i]; i++) {
83 if (strequal( prohibited_ea_names[i], unix_ea_name))
84 return true;
86 if (StrnCaseCmp(unix_ea_name, SAMBA_XATTR_DOSSTREAM_PREFIX,
87 strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) == 0) {
88 return true;
90 return false;
93 /****************************************************************************
94 Get one EA value. Fill in a struct ea_struct.
95 ****************************************************************************/
97 NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn,
98 files_struct *fsp, const char *fname,
99 const char *ea_name, struct ea_struct *pea)
101 /* Get the value of this xattr. Max size is 64k. */
102 size_t attr_size = 256;
103 char *val = NULL;
104 ssize_t sizeret;
106 again:
108 val = TALLOC_REALLOC_ARRAY(mem_ctx, val, char, attr_size);
109 if (!val) {
110 return NT_STATUS_NO_MEMORY;
113 if (fsp && fsp->fh->fd != -1) {
114 sizeret = SMB_VFS_FGETXATTR(fsp, ea_name, val, attr_size);
115 } else {
116 sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size);
119 if (sizeret == -1 && errno == ERANGE && attr_size != 65536) {
120 attr_size = 65536;
121 goto again;
124 if (sizeret == -1) {
125 return map_nt_error_from_unix(errno);
128 DEBUG(10,("get_ea_value: EA %s is of length %u\n", ea_name, (unsigned int)sizeret));
129 dump_data(10, (uint8 *)val, sizeret);
131 pea->flags = 0;
132 if (strnequal(ea_name, "user.", 5)) {
133 pea->name = talloc_strdup(mem_ctx, &ea_name[5]);
134 } else {
135 pea->name = talloc_strdup(mem_ctx, ea_name);
137 if (pea->name == NULL) {
138 TALLOC_FREE(val);
139 return NT_STATUS_NO_MEMORY;
141 pea->value.data = (unsigned char *)val;
142 pea->value.length = (size_t)sizeret;
143 return NT_STATUS_OK;
146 NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
147 files_struct *fsp, const char *fname,
148 char ***pnames, size_t *pnum_names)
150 /* Get a list of all xattrs. Max namesize is 64k. */
151 size_t ea_namelist_size = 1024;
152 char *ea_namelist = NULL;
154 char *p;
155 char **names, **tmp;
156 size_t num_names;
157 ssize_t sizeret = -1;
159 if (!lp_ea_support(SNUM(conn))) {
160 if (pnames) {
161 *pnames = NULL;
163 *pnum_names = 0;
164 return NT_STATUS_OK;
168 * TALLOC the result early to get the talloc hierarchy right.
171 names = TALLOC_ARRAY(mem_ctx, char *, 1);
172 if (names == NULL) {
173 DEBUG(0, ("talloc failed\n"));
174 return NT_STATUS_NO_MEMORY;
177 while (ea_namelist_size <= 65536) {
179 ea_namelist = TALLOC_REALLOC_ARRAY(
180 names, ea_namelist, char, ea_namelist_size);
181 if (ea_namelist == NULL) {
182 DEBUG(0, ("talloc failed\n"));
183 TALLOC_FREE(names);
184 return NT_STATUS_NO_MEMORY;
187 if (fsp && fsp->fh->fd != -1) {
188 sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
189 ea_namelist_size);
190 } else {
191 sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist,
192 ea_namelist_size);
195 if ((sizeret == -1) && (errno == ERANGE)) {
196 ea_namelist_size *= 2;
198 else {
199 break;
203 if (sizeret == -1) {
204 TALLOC_FREE(names);
205 return map_nt_error_from_unix(errno);
208 DEBUG(10, ("get_ea_list_from_file: ea_namelist size = %u\n",
209 (unsigned int)sizeret));
211 if (sizeret == 0) {
212 TALLOC_FREE(names);
213 if (pnames) {
214 *pnames = NULL;
216 *pnum_names = 0;
217 return NT_STATUS_OK;
221 * Ensure the result is 0-terminated
224 if (ea_namelist[sizeret-1] != '\0') {
225 TALLOC_FREE(names);
226 return NT_STATUS_INTERNAL_ERROR;
230 * count the names
232 num_names = 0;
234 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
235 num_names += 1;
238 tmp = TALLOC_REALLOC_ARRAY(mem_ctx, names, char *, num_names);
239 if (tmp == NULL) {
240 DEBUG(0, ("talloc failed\n"));
241 TALLOC_FREE(names);
242 return NT_STATUS_NO_MEMORY;
245 names = tmp;
246 num_names = 0;
248 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
249 names[num_names++] = p;
252 if (pnames) {
253 *pnames = names;
254 } else {
255 TALLOC_FREE(names);
257 *pnum_names = num_names;
258 return NT_STATUS_OK;
261 /****************************************************************************
262 Return a linked list of the total EA's. Plus the total size
263 ****************************************************************************/
265 static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
266 const char *fname, size_t *pea_total_len)
268 /* Get a list of all xattrs. Max namesize is 64k. */
269 size_t i, num_names;
270 char **names;
271 struct ea_list *ea_list_head = NULL;
272 NTSTATUS status;
274 *pea_total_len = 0;
276 if (!lp_ea_support(SNUM(conn))) {
277 return NULL;
280 status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
281 &names, &num_names);
283 if (!NT_STATUS_IS_OK(status) || (num_names == 0)) {
284 return NULL;
287 for (i=0; i<num_names; i++) {
288 struct ea_list *listp;
289 fstring dos_ea_name;
291 if (strnequal(names[i], "system.", 7)
292 || samba_private_attr_name(names[i]))
293 continue;
295 listp = TALLOC_P(mem_ctx, struct ea_list);
296 if (listp == NULL) {
297 return NULL;
300 if (!NT_STATUS_IS_OK(get_ea_value(mem_ctx, conn, fsp,
301 fname, names[i],
302 &listp->ea))) {
303 return NULL;
306 push_ascii_fstring(dos_ea_name, listp->ea.name);
308 *pea_total_len +=
309 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
311 DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len "
312 "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
313 (unsigned int)listp->ea.value.length));
315 DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
319 /* Add on 4 for total length. */
320 if (*pea_total_len) {
321 *pea_total_len += 4;
324 DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
325 (unsigned int)*pea_total_len));
327 return ea_list_head;
330 /****************************************************************************
331 Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer
332 that was filled.
333 ****************************************************************************/
335 static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
336 connection_struct *conn, struct ea_list *ea_list)
338 unsigned int ret_data_size = 4;
339 char *p = pdata;
341 SMB_ASSERT(total_data_size >= 4);
343 if (!lp_ea_support(SNUM(conn))) {
344 SIVAL(pdata,4,0);
345 return 4;
348 for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
349 size_t dos_namelen;
350 fstring dos_ea_name;
351 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
352 dos_namelen = strlen(dos_ea_name);
353 if (dos_namelen > 255 || dos_namelen == 0) {
354 break;
356 if (ea_list->ea.value.length > 65535) {
357 break;
359 if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
360 break;
363 /* We know we have room. */
364 SCVAL(p,0,ea_list->ea.flags);
365 SCVAL(p,1,dos_namelen);
366 SSVAL(p,2,ea_list->ea.value.length);
367 fstrcpy(p+4, dos_ea_name);
368 memcpy( p + 4 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
370 total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
371 p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
374 ret_data_size = PTR_DIFF(p, pdata);
375 DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
376 SIVAL(pdata,0,ret_data_size);
377 return ret_data_size;
380 static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
381 char *pdata,
382 unsigned int total_data_size,
383 unsigned int *ret_data_size,
384 connection_struct *conn,
385 struct ea_list *ea_list)
387 uint8_t *p = (uint8_t *)pdata;
388 uint8_t *last_start = NULL;
390 *ret_data_size = 0;
392 if (!lp_ea_support(SNUM(conn))) {
393 return NT_STATUS_NO_EAS_ON_FILE;
396 for (; ea_list; ea_list = ea_list->next) {
397 size_t dos_namelen;
398 fstring dos_ea_name;
399 size_t this_size;
401 if (last_start) {
402 SIVAL(last_start, 0, PTR_DIFF(p, last_start));
404 last_start = p;
406 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
407 dos_namelen = strlen(dos_ea_name);
408 if (dos_namelen > 255 || dos_namelen == 0) {
409 return NT_STATUS_INTERNAL_ERROR;
411 if (ea_list->ea.value.length > 65535) {
412 return NT_STATUS_INTERNAL_ERROR;
415 this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length;
417 if (ea_list->next) {
418 size_t pad = 4 - (this_size % 4);
419 this_size += pad;
422 if (this_size > total_data_size) {
423 return NT_STATUS_INFO_LENGTH_MISMATCH;
426 /* We know we have room. */
427 SIVAL(p, 0x00, 0); /* next offset */
428 SCVAL(p, 0x04, ea_list->ea.flags);
429 SCVAL(p, 0x05, dos_namelen);
430 SSVAL(p, 0x06, ea_list->ea.value.length);
431 fstrcpy((char *)(p+0x08), dos_ea_name);
432 memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
434 total_data_size -= this_size;
435 p += this_size;
438 *ret_data_size = PTR_DIFF(p, pdata);
439 DEBUG(10,("fill_ea_chained_buffer: data_size = %u\n", *ret_data_size));
440 return NT_STATUS_OK;
443 static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname)
445 size_t total_ea_len = 0;
446 TALLOC_CTX *mem_ctx = NULL;
448 if (!lp_ea_support(SNUM(conn))) {
449 return 0;
451 mem_ctx = talloc_tos();
452 (void)get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
453 return total_ea_len;
456 /****************************************************************************
457 Ensure the EA name is case insensitive by matching any existing EA name.
458 ****************************************************************************/
460 static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, const char *fname, fstring unix_ea_name)
462 size_t total_ea_len;
463 TALLOC_CTX *mem_ctx = talloc_tos();
464 struct ea_list *ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
466 for (; ea_list; ea_list = ea_list->next) {
467 if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
468 DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
469 &unix_ea_name[5], ea_list->ea.name));
470 safe_strcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-6);
471 break;
476 /****************************************************************************
477 Set or delete an extended attribute.
478 ****************************************************************************/
480 NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
481 const struct smb_filename *smb_fname, struct ea_list *ea_list)
483 char *fname = NULL;
485 if (!lp_ea_support(SNUM(conn))) {
486 return NT_STATUS_EAS_NOT_SUPPORTED;
489 /* For now setting EAs on streams isn't supported. */
490 fname = smb_fname->base_name;
492 for (;ea_list; ea_list = ea_list->next) {
493 int ret;
494 fstring unix_ea_name;
496 fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
497 fstrcat(unix_ea_name, ea_list->ea.name);
499 canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
501 DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
503 if (samba_private_attr_name(unix_ea_name)) {
504 DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
505 return NT_STATUS_ACCESS_DENIED;
508 if (ea_list->ea.value.length == 0) {
509 /* Remove the attribute. */
510 if (fsp && (fsp->fh->fd != -1)) {
511 DEBUG(10,("set_ea: deleting ea name %s on "
512 "file %s by file descriptor.\n",
513 unix_ea_name, fsp_str_dbg(fsp)));
514 ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name);
515 } else {
516 DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",
517 unix_ea_name, fname));
518 ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);
520 #ifdef ENOATTR
521 /* Removing a non existent attribute always succeeds. */
522 if (ret == -1 && errno == ENOATTR) {
523 DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",
524 unix_ea_name));
525 ret = 0;
527 #endif
528 } else {
529 if (fsp && (fsp->fh->fd != -1)) {
530 DEBUG(10,("set_ea: setting ea name %s on file "
531 "%s by file descriptor.\n",
532 unix_ea_name, fsp_str_dbg(fsp)));
533 ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name,
534 ea_list->ea.value.data, ea_list->ea.value.length, 0);
535 } else {
536 DEBUG(10,("set_ea: setting ea name %s on file %s.\n",
537 unix_ea_name, fname));
538 ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name,
539 ea_list->ea.value.data, ea_list->ea.value.length, 0);
543 if (ret == -1) {
544 #ifdef ENOTSUP
545 if (errno == ENOTSUP) {
546 return NT_STATUS_EAS_NOT_SUPPORTED;
548 #endif
549 return map_nt_error_from_unix(errno);
553 return NT_STATUS_OK;
555 /****************************************************************************
556 Read a list of EA names from an incoming data buffer. Create an ea_list with them.
557 ****************************************************************************/
559 static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
561 struct ea_list *ea_list_head = NULL;
562 size_t converted_size, offset = 0;
564 while (offset + 2 < data_size) {
565 struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
566 unsigned int namelen = CVAL(pdata,offset);
568 offset++; /* Go past the namelen byte. */
570 /* integer wrap paranioa. */
571 if ((offset + namelen < offset) || (offset + namelen < namelen) ||
572 (offset > data_size) || (namelen > data_size) ||
573 (offset + namelen >= data_size)) {
574 break;
576 /* Ensure the name is null terminated. */
577 if (pdata[offset + namelen] != '\0') {
578 return NULL;
580 if (!pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset],
581 &converted_size)) {
582 DEBUG(0,("read_ea_name_list: pull_ascii_talloc "
583 "failed: %s", strerror(errno)));
585 if (!eal->ea.name) {
586 return NULL;
589 offset += (namelen + 1); /* Go past the name + terminating zero. */
590 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
591 DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
594 return ea_list_head;
597 /****************************************************************************
598 Read one EA list entry from the buffer.
599 ****************************************************************************/
601 struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used)
603 struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
604 uint16 val_len;
605 unsigned int namelen;
606 size_t converted_size;
608 if (!eal) {
609 return NULL;
612 if (data_size < 6) {
613 return NULL;
616 eal->ea.flags = CVAL(pdata,0);
617 namelen = CVAL(pdata,1);
618 val_len = SVAL(pdata,2);
620 if (4 + namelen + 1 + val_len > data_size) {
621 return NULL;
624 /* Ensure the name is null terminated. */
625 if (pdata[namelen + 4] != '\0') {
626 return NULL;
628 if (!pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4, &converted_size)) {
629 DEBUG(0,("read_ea_list_entry: pull_ascii_talloc failed: %s",
630 strerror(errno)));
632 if (!eal->ea.name) {
633 return NULL;
636 eal->ea.value = data_blob_talloc(eal, NULL, (size_t)val_len + 1);
637 if (!eal->ea.value.data) {
638 return NULL;
641 memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len);
643 /* Ensure we're null terminated just in case we print the value. */
644 eal->ea.value.data[val_len] = '\0';
645 /* But don't count the null. */
646 eal->ea.value.length--;
648 if (pbytes_used) {
649 *pbytes_used = 4 + namelen + 1 + val_len;
652 DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name));
653 dump_data(10, eal->ea.value.data, eal->ea.value.length);
655 return eal;
658 /****************************************************************************
659 Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
660 ****************************************************************************/
662 static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
664 struct ea_list *ea_list_head = NULL;
665 size_t offset = 0;
666 size_t bytes_used = 0;
668 while (offset < data_size) {
669 struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);
671 if (!eal) {
672 return NULL;
675 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
676 offset += bytes_used;
679 return ea_list_head;
682 /****************************************************************************
683 Count the total EA size needed.
684 ****************************************************************************/
686 static size_t ea_list_size(struct ea_list *ealist)
688 fstring dos_ea_name;
689 struct ea_list *listp;
690 size_t ret = 0;
692 for (listp = ealist; listp; listp = listp->next) {
693 push_ascii_fstring(dos_ea_name, listp->ea.name);
694 ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
696 /* Add on 4 for total length. */
697 if (ret) {
698 ret += 4;
701 return ret;
704 /****************************************************************************
705 Return a union of EA's from a file list and a list of names.
706 The TALLOC context for the two lists *MUST* be identical as we steal
707 memory from one list to add to another. JRA.
708 ****************************************************************************/
710 static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *file_list, size_t *total_ea_len)
712 struct ea_list *nlistp, *flistp;
714 for (nlistp = name_list; nlistp; nlistp = nlistp->next) {
715 for (flistp = file_list; flistp; flistp = flistp->next) {
716 if (strequal(nlistp->ea.name, flistp->ea.name)) {
717 break;
721 if (flistp) {
722 /* Copy the data from this entry. */
723 nlistp->ea.flags = flistp->ea.flags;
724 nlistp->ea.value = flistp->ea.value;
725 } else {
726 /* Null entry. */
727 nlistp->ea.flags = 0;
728 ZERO_STRUCT(nlistp->ea.value);
732 *total_ea_len = ea_list_size(name_list);
733 return name_list;
736 /****************************************************************************
737 Send the required number of replies back.
738 We assume all fields other than the data fields are
739 set correctly for the type of call.
740 HACK ! Always assumes smb_setup field is zero.
741 ****************************************************************************/
743 void send_trans2_replies(connection_struct *conn,
744 struct smb_request *req,
745 const char *params,
746 int paramsize,
747 const char *pdata,
748 int datasize,
749 int max_data_bytes)
751 /* As we are using a protocol > LANMAN1 then the max_send
752 variable must have been set in the sessetupX call.
753 This takes precedence over the max_xmit field in the
754 global struct. These different max_xmit variables should
755 be merged as this is now too confusing */
757 int data_to_send = datasize;
758 int params_to_send = paramsize;
759 int useable_space;
760 const char *pp = params;
761 const char *pd = pdata;
762 int params_sent_thistime, data_sent_thistime, total_sent_thistime;
763 int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
764 int data_alignment_offset = 0;
765 bool overflow = False;
766 struct smbd_server_connection *sconn = smbd_server_conn;
767 int max_send = sconn->smb1.sessions.max_send;
769 /* Modify the data_to_send and datasize and set the error if
770 we're trying to send more than max_data_bytes. We still send
771 the part of the packet(s) that fit. Strange, but needed
772 for OS/2. */
774 if (max_data_bytes > 0 && datasize > max_data_bytes) {
775 DEBUG(5,("send_trans2_replies: max_data_bytes %d exceeded by data %d\n",
776 max_data_bytes, datasize ));
777 datasize = data_to_send = max_data_bytes;
778 overflow = True;
781 /* If there genuinely are no parameters or data to send just send the empty packet */
783 if(params_to_send == 0 && data_to_send == 0) {
784 reply_outbuf(req, 10, 0);
785 show_msg((char *)req->outbuf);
786 if (!srv_send_smb(smbd_server_fd(),
787 (char *)req->outbuf,
788 true, req->seqnum+1,
789 IS_CONN_ENCRYPTED(conn),
790 &req->pcd)) {
791 exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
793 TALLOC_FREE(req->outbuf);
794 return;
797 /* When sending params and data ensure that both are nicely aligned */
798 /* Only do this alignment when there is also data to send - else
799 can cause NT redirector problems. */
801 if (((params_to_send % 4) != 0) && (data_to_send != 0))
802 data_alignment_offset = 4 - (params_to_send % 4);
804 /* Space is bufsize minus Netbios over TCP header minus SMB header */
805 /* The alignment_offset is to align the param bytes on an even byte
806 boundary. NT 4.0 Beta needs this to work correctly. */
808 useable_space = max_send - (smb_size
809 + 2 * 10 /* wct */
810 + alignment_offset
811 + data_alignment_offset);
813 if (useable_space < 0) {
814 DEBUG(0, ("send_trans2_replies failed sanity useable_space "
815 "= %d!!!", useable_space));
816 exit_server_cleanly("send_trans2_replies: Not enough space");
819 while (params_to_send || data_to_send) {
820 /* Calculate whether we will totally or partially fill this packet */
822 total_sent_thistime = params_to_send + data_to_send;
824 /* We can never send more than useable_space */
826 * Note that 'useable_space' does not include the alignment offsets,
827 * but we must include the alignment offsets in the calculation of
828 * the length of the data we send over the wire, as the alignment offsets
829 * are sent here. Fix from Marc_Jacobsen@hp.com.
832 total_sent_thistime = MIN(total_sent_thistime, useable_space);
834 reply_outbuf(req, 10, total_sent_thistime + alignment_offset
835 + data_alignment_offset);
838 * We might have SMBtrans2s in req which was transferred to
839 * the outbuf, fix that.
841 SCVAL(req->outbuf, smb_com, SMBtrans2);
843 /* Set total params and data to be sent */
844 SSVAL(req->outbuf,smb_tprcnt,paramsize);
845 SSVAL(req->outbuf,smb_tdrcnt,datasize);
847 /* Calculate how many parameters and data we can fit into
848 * this packet. Parameters get precedence
851 params_sent_thistime = MIN(params_to_send,useable_space);
852 data_sent_thistime = useable_space - params_sent_thistime;
853 data_sent_thistime = MIN(data_sent_thistime,data_to_send);
855 SSVAL(req->outbuf,smb_prcnt, params_sent_thistime);
857 /* smb_proff is the offset from the start of the SMB header to the
858 parameter bytes, however the first 4 bytes of outbuf are
859 the Netbios over TCP header. Thus use smb_base() to subtract
860 them from the calculation */
862 SSVAL(req->outbuf,smb_proff,
863 ((smb_buf(req->outbuf)+alignment_offset)
864 - smb_base(req->outbuf)));
866 if(params_sent_thistime == 0)
867 SSVAL(req->outbuf,smb_prdisp,0);
868 else
869 /* Absolute displacement of param bytes sent in this packet */
870 SSVAL(req->outbuf,smb_prdisp,pp - params);
872 SSVAL(req->outbuf,smb_drcnt, data_sent_thistime);
873 if(data_sent_thistime == 0) {
874 SSVAL(req->outbuf,smb_droff,0);
875 SSVAL(req->outbuf,smb_drdisp, 0);
876 } else {
877 /* The offset of the data bytes is the offset of the
878 parameter bytes plus the number of parameters being sent this time */
879 SSVAL(req->outbuf, smb_droff,
880 ((smb_buf(req->outbuf)+alignment_offset)
881 - smb_base(req->outbuf))
882 + params_sent_thistime + data_alignment_offset);
883 SSVAL(req->outbuf,smb_drdisp, pd - pdata);
886 /* Initialize the padding for alignment */
888 if (alignment_offset != 0) {
889 memset(smb_buf(req->outbuf), 0, alignment_offset);
892 /* Copy the param bytes into the packet */
894 if(params_sent_thistime) {
895 memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
896 params_sent_thistime);
899 /* Copy in the data bytes */
900 if(data_sent_thistime) {
901 if (data_alignment_offset != 0) {
902 memset((smb_buf(req->outbuf)+alignment_offset+
903 params_sent_thistime), 0,
904 data_alignment_offset);
906 memcpy(smb_buf(req->outbuf)+alignment_offset
907 +params_sent_thistime+data_alignment_offset,
908 pd,data_sent_thistime);
911 DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
912 params_sent_thistime, data_sent_thistime, useable_space));
913 DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
914 params_to_send, data_to_send, paramsize, datasize));
916 if (overflow) {
917 error_packet_set((char *)req->outbuf,
918 ERRDOS,ERRbufferoverflow,
919 STATUS_BUFFER_OVERFLOW,
920 __LINE__,__FILE__);
923 /* Send the packet */
924 show_msg((char *)req->outbuf);
925 if (!srv_send_smb(smbd_server_fd(),
926 (char *)req->outbuf,
927 true, req->seqnum+1,
928 IS_CONN_ENCRYPTED(conn),
929 &req->pcd))
930 exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
932 TALLOC_FREE(req->outbuf);
934 pp += params_sent_thistime;
935 pd += data_sent_thistime;
937 params_to_send -= params_sent_thistime;
938 data_to_send -= data_sent_thistime;
940 /* Sanity check */
941 if(params_to_send < 0 || data_to_send < 0) {
942 DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
943 params_to_send, data_to_send));
944 return;
948 return;
951 /****************************************************************************
952 Reply to a TRANSACT2_OPEN.
953 ****************************************************************************/
955 static void call_trans2open(connection_struct *conn,
956 struct smb_request *req,
957 char **pparams, int total_params,
958 char **ppdata, int total_data,
959 unsigned int max_data_bytes)
961 struct smb_filename *smb_fname = NULL;
962 char *params = *pparams;
963 char *pdata = *ppdata;
964 int deny_mode;
965 int32 open_attr;
966 bool oplock_request;
967 #if 0
968 bool return_additional_info;
969 int16 open_sattr;
970 time_t open_time;
971 #endif
972 int open_ofun;
973 uint32 open_size;
974 char *pname;
975 char *fname = NULL;
976 SMB_OFF_T size=0;
977 int fattr=0,mtime=0;
978 SMB_INO_T inode = 0;
979 int smb_action = 0;
980 files_struct *fsp;
981 struct ea_list *ea_list = NULL;
982 uint16 flags = 0;
983 NTSTATUS status;
984 uint32 access_mask;
985 uint32 share_mode;
986 uint32 create_disposition;
987 uint32 create_options = 0;
988 TALLOC_CTX *ctx = talloc_tos();
991 * Ensure we have enough parameters to perform the operation.
994 if (total_params < 29) {
995 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
996 goto out;
999 flags = SVAL(params, 0);
1000 deny_mode = SVAL(params, 2);
1001 open_attr = SVAL(params,6);
1002 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
1003 if (oplock_request) {
1004 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
1007 #if 0
1008 return_additional_info = BITSETW(params,0);
1009 open_sattr = SVAL(params, 4);
1010 open_time = make_unix_date3(params+8);
1011 #endif
1012 open_ofun = SVAL(params,12);
1013 open_size = IVAL(params,14);
1014 pname = &params[28];
1016 if (IS_IPC(conn)) {
1017 reply_doserror(req, ERRSRV, ERRaccess);
1018 goto out;
1021 srvstr_get_path(ctx, params, req->flags2, &fname, pname,
1022 total_params - 28, STR_TERMINATE,
1023 &status);
1024 if (!NT_STATUS_IS_OK(status)) {
1025 reply_nterror(req, status);
1026 goto out;
1029 DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n",
1030 fname, (unsigned int)deny_mode, (unsigned int)open_attr,
1031 (unsigned int)open_ofun, open_size));
1033 status = filename_convert(ctx,
1034 conn,
1035 req->flags2 & FLAGS2_DFS_PATHNAMES,
1036 fname,
1038 NULL,
1039 &smb_fname);
1040 if (!NT_STATUS_IS_OK(status)) {
1041 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1042 reply_botherror(req,
1043 NT_STATUS_PATH_NOT_COVERED,
1044 ERRSRV, ERRbadpath);
1045 goto out;
1047 reply_nterror(req, status);
1048 goto out;
1051 if (open_ofun == 0) {
1052 reply_nterror(req, NT_STATUS_OBJECT_NAME_COLLISION);
1053 goto out;
1056 if (!map_open_params_to_ntcreate(smb_fname, deny_mode, open_ofun,
1057 &access_mask, &share_mode,
1058 &create_disposition,
1059 &create_options)) {
1060 reply_doserror(req, ERRDOS, ERRbadaccess);
1061 goto out;
1064 /* Any data in this call is an EA list. */
1065 if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
1066 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
1067 goto out;
1070 if (total_data != 4) {
1071 if (total_data < 10) {
1072 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1073 goto out;
1076 if (IVAL(pdata,0) > total_data) {
1077 DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n",
1078 IVAL(pdata,0), (unsigned int)total_data));
1079 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1080 goto out;
1083 ea_list = read_ea_list(talloc_tos(), pdata + 4,
1084 total_data - 4);
1085 if (!ea_list) {
1086 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1087 goto out;
1089 } else if (IVAL(pdata,0) != 4) {
1090 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1091 goto out;
1094 status = SMB_VFS_CREATE_FILE(
1095 conn, /* conn */
1096 req, /* req */
1097 0, /* root_dir_fid */
1098 smb_fname, /* fname */
1099 access_mask, /* access_mask */
1100 share_mode, /* share_access */
1101 create_disposition, /* create_disposition*/
1102 create_options, /* create_options */
1103 open_attr, /* file_attributes */
1104 oplock_request, /* oplock_request */
1105 open_size, /* allocation_size */
1106 NULL, /* sd */
1107 ea_list, /* ea_list */
1108 &fsp, /* result */
1109 &smb_action); /* psbuf */
1111 if (!NT_STATUS_IS_OK(status)) {
1112 if (open_was_deferred(req->mid)) {
1113 /* We have re-scheduled this call. */
1114 goto out;
1116 reply_openerror(req, status);
1117 goto out;
1120 size = get_file_size_stat(&smb_fname->st);
1121 fattr = dos_mode(conn, smb_fname);
1122 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1123 inode = smb_fname->st.st_ex_ino;
1124 if (fattr & aDIR) {
1125 close_file(req, fsp, ERROR_CLOSE);
1126 reply_doserror(req, ERRDOS,ERRnoaccess);
1127 goto out;
1130 /* Realloc the size of parameters and data we will return */
1131 *pparams = (char *)SMB_REALLOC(*pparams, 30);
1132 if(*pparams == NULL ) {
1133 reply_nterror(req, NT_STATUS_NO_MEMORY);
1134 goto out;
1136 params = *pparams;
1138 SSVAL(params,0,fsp->fnum);
1139 SSVAL(params,2,fattr);
1140 srv_put_dos_date2(params,4, mtime);
1141 SIVAL(params,8, (uint32)size);
1142 SSVAL(params,12,deny_mode);
1143 SSVAL(params,14,0); /* open_type - file or directory. */
1144 SSVAL(params,16,0); /* open_state - only valid for IPC device. */
1146 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1147 smb_action |= EXTENDED_OPLOCK_GRANTED;
1150 SSVAL(params,18,smb_action);
1153 * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
1155 SIVAL(params,20,inode);
1156 SSVAL(params,24,0); /* Padding. */
1157 if (flags & 8) {
1158 uint32 ea_size = estimate_ea_size(conn, fsp,
1159 fsp->fsp_name->base_name);
1160 SIVAL(params, 26, ea_size);
1161 } else {
1162 SIVAL(params, 26, 0);
1165 /* Send the required number of replies */
1166 send_trans2_replies(conn, req, params, 30, *ppdata, 0, max_data_bytes);
1167 out:
1168 TALLOC_FREE(smb_fname);
1171 /*********************************************************
1172 Routine to check if a given string matches exactly.
1173 as a special case a mask of "." does NOT match. That
1174 is required for correct wildcard semantics
1175 Case can be significant or not.
1176 **********************************************************/
1178 static bool exact_match(bool has_wild,
1179 bool case_sensitive,
1180 const char *str,
1181 const char *mask)
1183 if (mask[0] == '.' && mask[1] == 0) {
1184 return false;
1187 if (has_wild) {
1188 return false;
1191 if (case_sensitive) {
1192 return strcmp(str,mask)==0;
1193 } else {
1194 return StrCaseCmp(str,mask) == 0;
1198 /****************************************************************************
1199 Return the filetype for UNIX extensions.
1200 ****************************************************************************/
1202 static uint32 unix_filetype(mode_t mode)
1204 if(S_ISREG(mode))
1205 return UNIX_TYPE_FILE;
1206 else if(S_ISDIR(mode))
1207 return UNIX_TYPE_DIR;
1208 #ifdef S_ISLNK
1209 else if(S_ISLNK(mode))
1210 return UNIX_TYPE_SYMLINK;
1211 #endif
1212 #ifdef S_ISCHR
1213 else if(S_ISCHR(mode))
1214 return UNIX_TYPE_CHARDEV;
1215 #endif
1216 #ifdef S_ISBLK
1217 else if(S_ISBLK(mode))
1218 return UNIX_TYPE_BLKDEV;
1219 #endif
1220 #ifdef S_ISFIFO
1221 else if(S_ISFIFO(mode))
1222 return UNIX_TYPE_FIFO;
1223 #endif
1224 #ifdef S_ISSOCK
1225 else if(S_ISSOCK(mode))
1226 return UNIX_TYPE_SOCKET;
1227 #endif
1229 DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode));
1230 return UNIX_TYPE_UNKNOWN;
1233 /****************************************************************************
1234 Map wire perms onto standard UNIX permissions. Obey share restrictions.
1235 ****************************************************************************/
1237 enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_DIR};
1239 static NTSTATUS unix_perms_from_wire( connection_struct *conn,
1240 const SMB_STRUCT_STAT *psbuf,
1241 uint32 perms,
1242 enum perm_type ptype,
1243 mode_t *ret_perms)
1245 mode_t ret = 0;
1247 if (perms == SMB_MODE_NO_CHANGE) {
1248 if (!VALID_STAT(*psbuf)) {
1249 return NT_STATUS_INVALID_PARAMETER;
1250 } else {
1251 *ret_perms = psbuf->st_ex_mode;
1252 return NT_STATUS_OK;
1256 ret |= ((perms & UNIX_X_OTH ) ? S_IXOTH : 0);
1257 ret |= ((perms & UNIX_W_OTH ) ? S_IWOTH : 0);
1258 ret |= ((perms & UNIX_R_OTH ) ? S_IROTH : 0);
1259 ret |= ((perms & UNIX_X_GRP ) ? S_IXGRP : 0);
1260 ret |= ((perms & UNIX_W_GRP ) ? S_IWGRP : 0);
1261 ret |= ((perms & UNIX_R_GRP ) ? S_IRGRP : 0);
1262 ret |= ((perms & UNIX_X_USR ) ? S_IXUSR : 0);
1263 ret |= ((perms & UNIX_W_USR ) ? S_IWUSR : 0);
1264 ret |= ((perms & UNIX_R_USR ) ? S_IRUSR : 0);
1265 #ifdef S_ISVTX
1266 ret |= ((perms & UNIX_STICKY ) ? S_ISVTX : 0);
1267 #endif
1268 #ifdef S_ISGID
1269 ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0);
1270 #endif
1271 #ifdef S_ISUID
1272 ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0);
1273 #endif
1275 switch (ptype) {
1276 case PERM_NEW_FILE:
1277 /* Apply mode mask */
1278 ret &= lp_create_mask(SNUM(conn));
1279 /* Add in force bits */
1280 ret |= lp_force_create_mode(SNUM(conn));
1281 break;
1282 case PERM_NEW_DIR:
1283 ret &= lp_dir_mask(SNUM(conn));
1284 /* Add in force bits */
1285 ret |= lp_force_dir_mode(SNUM(conn));
1286 break;
1287 case PERM_EXISTING_FILE:
1288 /* Apply mode mask */
1289 ret &= lp_security_mask(SNUM(conn));
1290 /* Add in force bits */
1291 ret |= lp_force_security_mode(SNUM(conn));
1292 break;
1293 case PERM_EXISTING_DIR:
1294 /* Apply mode mask */
1295 ret &= lp_dir_security_mask(SNUM(conn));
1296 /* Add in force bits */
1297 ret |= lp_force_dir_security_mode(SNUM(conn));
1298 break;
1301 *ret_perms = ret;
1302 return NT_STATUS_OK;
1305 /****************************************************************************
1306 Needed to show the msdfs symlinks as directories. Modifies psbuf
1307 to be a directory if it's a msdfs link.
1308 ****************************************************************************/
1310 static bool check_msdfs_link(connection_struct *conn,
1311 const char *pathname,
1312 SMB_STRUCT_STAT *psbuf)
1314 int saved_errno = errno;
1315 if(lp_host_msdfs() &&
1316 lp_msdfs_root(SNUM(conn)) &&
1317 is_msdfs_link(conn, pathname, psbuf)) {
1319 DEBUG(5,("check_msdfs_link: Masquerading msdfs link %s "
1320 "as a directory\n",
1321 pathname));
1322 psbuf->st_ex_mode = (psbuf->st_ex_mode & 0xFFF) | S_IFDIR;
1323 errno = saved_errno;
1324 return true;
1326 errno = saved_errno;
1327 return false;
1331 /****************************************************************************
1332 Get a level dependent lanman2 dir entry.
1333 ****************************************************************************/
1335 struct smbd_dirptr_lanman2_state {
1336 connection_struct *conn;
1337 uint32_t info_level;
1338 bool check_mangled_names;
1339 bool has_wild;
1340 bool got_exact_match;
1343 static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx,
1344 void *private_data,
1345 const char *dname,
1346 const char *mask,
1347 char **_fname)
1349 struct smbd_dirptr_lanman2_state *state =
1350 (struct smbd_dirptr_lanman2_state *)private_data;
1351 bool ok;
1352 char mangled_name[13]; /* mangled 8.3 name. */
1353 bool got_match;
1354 const char *fname;
1356 /* Mangle fname if it's an illegal name. */
1357 if (mangle_must_mangle(dname, state->conn->params)) {
1358 ok = name_to_8_3(dname, mangled_name,
1359 true, state->conn->params);
1360 if (!ok) {
1361 return false;
1363 fname = mangled_name;
1364 } else {
1365 fname = dname;
1368 got_match = exact_match(state->has_wild,
1369 state->conn->case_sensitive,
1370 fname, mask);
1371 state->got_exact_match = got_match;
1372 if (!got_match) {
1373 got_match = mask_match(fname, mask,
1374 state->conn->case_sensitive);
1377 if(!got_match && state->check_mangled_names &&
1378 !mangle_is_8_3(fname, false, state->conn->params)) {
1380 * It turns out that NT matches wildcards against
1381 * both long *and* short names. This may explain some
1382 * of the wildcard wierdness from old DOS clients
1383 * that some people have been seeing.... JRA.
1385 /* Force the mangling into 8.3. */
1386 ok = name_to_8_3(fname, mangled_name,
1387 false, state->conn->params);
1388 if (!ok) {
1389 return false;
1392 got_match = exact_match(state->has_wild,
1393 state->conn->case_sensitive,
1394 mangled_name, mask);
1395 state->got_exact_match = got_match;
1396 if (!got_match) {
1397 got_match = mask_match(mangled_name, mask,
1398 state->conn->case_sensitive);
1402 if (!got_match) {
1403 return false;
1406 *_fname = talloc_strdup(ctx, fname);
1407 if (*_fname == NULL) {
1408 return false;
1411 return true;
1414 static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
1415 void *private_data,
1416 struct smb_filename *smb_fname,
1417 uint32_t *_mode)
1419 struct smbd_dirptr_lanman2_state *state =
1420 (struct smbd_dirptr_lanman2_state *)private_data;
1421 bool ms_dfs_link = false;
1422 uint32_t mode = 0;
1424 if (INFO_LEVEL_IS_UNIX(state->info_level)) {
1425 if (SMB_VFS_LSTAT(state->conn, smb_fname) != 0) {
1426 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1427 "Couldn't lstat [%s] (%s)\n",
1428 smb_fname_str_dbg(smb_fname),
1429 strerror(errno)));
1430 return false;
1432 } else if (!VALID_STAT(smb_fname->st) &&
1433 SMB_VFS_STAT(state->conn, smb_fname) != 0) {
1434 /* Needed to show the msdfs symlinks as
1435 * directories */
1437 ms_dfs_link = check_msdfs_link(state->conn,
1438 smb_fname->base_name,
1439 &smb_fname->st);
1440 if (!ms_dfs_link) {
1441 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1442 "Couldn't stat [%s] (%s)\n",
1443 smb_fname_str_dbg(smb_fname),
1444 strerror(errno)));
1445 return false;
1449 if (ms_dfs_link) {
1450 mode = dos_mode_msdfs(state->conn, smb_fname);
1451 } else {
1452 mode = dos_mode(state->conn, smb_fname);
1455 *_mode = mode;
1456 return true;
1459 static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
1460 connection_struct *conn,
1461 uint16_t flags2,
1462 uint32_t info_level,
1463 struct ea_list *name_list,
1464 bool check_mangled_names,
1465 bool requires_resume_key,
1466 uint32_t mode,
1467 const char *fname,
1468 const struct smb_filename *smb_fname,
1469 uint64_t space_remaining,
1470 uint8_t align,
1471 bool do_pad,
1472 char *base_data,
1473 char **ppdata,
1474 char *end_data,
1475 bool *out_of_space,
1476 uint64_t *last_entry_off)
1478 char *p, *q, *pdata = *ppdata;
1479 uint32_t reskey=0;
1480 uint64_t file_size = 0;
1481 uint64_t allocation_size = 0;
1482 uint32_t len;
1483 struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts;
1484 time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
1485 time_t c_date = (time_t)0;
1486 char *nameptr;
1487 char *last_entry_ptr;
1488 bool was_8_3;
1489 uint32_t nt_extmode; /* Used for NT connections instead of mode */
1490 off_t off;
1491 off_t pad = 0;
1493 *out_of_space = false;
1495 ZERO_STRUCT(mdate_ts);
1496 ZERO_STRUCT(adate_ts);
1497 ZERO_STRUCT(create_date_ts);
1498 ZERO_STRUCT(cdate_ts);
1500 if (!(mode & aDIR)) {
1501 file_size = get_file_size_stat(&smb_fname->st);
1503 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
1505 mdate_ts = smb_fname->st.st_ex_mtime;
1506 adate_ts = smb_fname->st.st_ex_atime;
1507 create_date_ts = get_create_timespec(conn, NULL, smb_fname);
1508 cdate_ts = get_change_timespec(conn, NULL, smb_fname);
1510 if (lp_dos_filetime_resolution(SNUM(conn))) {
1511 dos_filetime_timespec(&create_date_ts);
1512 dos_filetime_timespec(&mdate_ts);
1513 dos_filetime_timespec(&adate_ts);
1514 dos_filetime_timespec(&cdate_ts);
1517 create_date = convert_timespec_to_time_t(create_date_ts);
1518 mdate = convert_timespec_to_time_t(mdate_ts);
1519 adate = convert_timespec_to_time_t(adate_ts);
1520 c_date = convert_timespec_to_time_t(cdate_ts);
1522 /* align the record */
1523 off = PTR_DIFF(pdata, base_data);
1524 pad = (off + (align-1)) & ~(align-1);
1525 pad -= off;
1526 off += pad;
1527 /* initialize padding to 0 */
1528 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,("get_lanman2_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,("get_lanman2_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,("get_lanman2_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,("get_lanman2_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,("get_lanman2_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,("get_lanman2_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,("get_lanman2_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,("get_lanman2_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,("get_lanman2_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,("get_lanman2_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,("get_lanman2_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,("get_lanman2_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,("get_lanman2_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 int 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 bool resume_key = false;
2162 const uint8_t align = 4;
2163 const bool do_pad = true;
2165 if (requires_resume_key) {
2166 resume_key = true;
2169 return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2,
2170 path_mask, dirtype, info_level,
2171 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 (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 srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name,
2579 params+12,
2580 total_params - 12, STR_TERMINATE, &ntstatus,
2581 &mask_contains_wcard);
2582 if (!NT_STATUS_IS_OK(ntstatus)) {
2583 /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
2584 complain (it thinks we're asking for the directory above the shared
2585 path or an invalid name). Catch this as the resume name is only compared, never used in
2586 a file access. JRA. */
2587 srvstr_pull_talloc(ctx, params, req->flags2,
2588 &resume_name, params+12,
2589 total_params - 12,
2590 STR_TERMINATE);
2592 if (!resume_name || !(ISDOT(resume_name) || ISDOTDOT(resume_name))) {
2593 reply_nterror(req, ntstatus);
2594 return;
2598 DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \
2599 close_after_request=%d, close_if_end = %d requires_resume_key = %d \
2600 resume_key = %d resume name = %s continue=%d level = %d\n",
2601 dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end,
2602 requires_resume_key, resume_key, resume_name, continue_bit, info_level));
2604 if (!maxentries) {
2605 /* W2K3 seems to treat zero as 1. */
2606 maxentries = 1;
2609 switch (info_level) {
2610 case SMB_FIND_INFO_STANDARD:
2611 case SMB_FIND_EA_SIZE:
2612 case SMB_FIND_EA_LIST:
2613 case SMB_FIND_FILE_DIRECTORY_INFO:
2614 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
2615 case SMB_FIND_FILE_NAMES_INFO:
2616 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
2617 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
2618 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
2619 break;
2620 case SMB_FIND_FILE_UNIX:
2621 case SMB_FIND_FILE_UNIX_INFO2:
2622 /* Always use filesystem for UNIX mtime query. */
2623 ask_sharemode = false;
2624 if (!lp_unix_extensions()) {
2625 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2626 return;
2628 break;
2629 default:
2630 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2631 return;
2634 if (info_level == SMB_FIND_EA_LIST) {
2635 uint32 ea_size;
2637 if (total_data < 4) {
2638 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2639 return;
2642 ea_size = IVAL(pdata,0);
2643 if (ea_size != total_data) {
2644 DEBUG(4,("call_trans2findnext: Rejecting EA request with incorrect \
2645 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2646 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2647 return;
2650 if (!lp_ea_support(SNUM(conn))) {
2651 reply_doserror(req, ERRDOS, ERReasnotsupported);
2652 return;
2655 /* Pull out the list of names. */
2656 ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
2657 if (!ea_list) {
2658 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2659 return;
2663 *ppdata = (char *)SMB_REALLOC(
2664 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2665 if(*ppdata == NULL) {
2666 reply_nterror(req, NT_STATUS_NO_MEMORY);
2667 return;
2670 pdata = *ppdata;
2671 data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2673 /* Realloc the params space */
2674 *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD);
2675 if(*pparams == NULL ) {
2676 reply_nterror(req, NT_STATUS_NO_MEMORY);
2677 return;
2680 params = *pparams;
2682 /* Check that the dptr is valid */
2683 if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) {
2684 reply_doserror(req, ERRDOS, ERRnofiles);
2685 return;
2688 directory = dptr_path(sconn, dptr_num);
2690 /* Get the wildcard mask from the dptr */
2691 if((p = dptr_wcard(sconn, dptr_num))== NULL) {
2692 DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
2693 reply_doserror(req, ERRDOS, ERRnofiles);
2694 return;
2697 mask = p;
2699 /* Get the attr mask from the dptr */
2700 dirtype = dptr_attr(sconn, dptr_num);
2702 DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld)\n",
2703 dptr_num, mask, dirtype,
2704 (long)dirptr,
2705 dptr_TellDir(dirptr)));
2707 /* Initialize per TRANS2_FIND_NEXT operation data */
2708 dptr_init_search_op(dirptr);
2710 /* We don't need to check for VOL here as this is returned by
2711 a different TRANS2 call. */
2713 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
2714 directory,lp_dontdescend(SNUM(conn))));
2715 if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
2716 dont_descend = True;
2718 p = pdata;
2719 space_remaining = max_data_bytes;
2720 out_of_space = False;
2723 * Seek to the correct position. We no longer use the resume key but
2724 * depend on the last file name instead.
2727 if(*resume_name && !continue_bit) {
2728 SMB_STRUCT_STAT st;
2730 long current_pos = 0;
2732 * Remember, name_to_8_3 is called by
2733 * get_lanman2_dir_entry(), so the resume name
2734 * could be mangled. Ensure we check the unmangled name.
2737 if (mangle_is_mangled(resume_name, conn->params)) {
2738 char *new_resume_name = NULL;
2739 mangle_lookup_name_from_8_3(ctx,
2740 resume_name,
2741 &new_resume_name,
2742 conn->params);
2743 if (new_resume_name) {
2744 resume_name = new_resume_name;
2749 * Fix for NT redirector problem triggered by resume key indexes
2750 * changing between directory scans. We now return a resume key of 0
2751 * and instead look for the filename to continue from (also given
2752 * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
2753 * findfirst/findnext (as is usual) then the directory pointer
2754 * should already be at the correct place.
2757 finished = !dptr_SearchDir(dirptr, resume_name, &current_pos, &st);
2758 } /* end if resume_name && !continue_bit */
2760 for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
2761 bool got_exact_match = False;
2763 /* this is a heuristic to avoid seeking the dirptr except when
2764 absolutely necessary. It allows for a filename of about 40 chars */
2765 if (space_remaining < DIRLEN_GUESS && numentries > 0) {
2766 out_of_space = True;
2767 finished = False;
2768 } else {
2769 finished = !get_lanman2_dir_entry(ctx,
2770 conn,
2771 dirptr,
2772 req->flags2,
2773 mask,dirtype,info_level,
2774 requires_resume_key,dont_descend,
2775 ask_sharemode,
2776 &p,pdata,data_end,
2777 space_remaining, &out_of_space,
2778 &got_exact_match,
2779 &last_entry_off, ea_list);
2782 if (finished && out_of_space)
2783 finished = False;
2785 if (!finished && !out_of_space)
2786 numentries++;
2789 * As an optimisation if we know we aren't looking
2790 * for a wildcard name (ie. the name matches the wildcard exactly)
2791 * then we can finish on any (first) match.
2792 * This speeds up large directory searches. JRA.
2795 if(got_exact_match)
2796 finished = True;
2798 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
2801 DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
2802 smb_fn_name(req->cmd),
2803 mask, directory, dirtype, numentries ) );
2805 /* Check if we can close the dirptr */
2806 if(close_after_request || (finished && close_if_end)) {
2807 DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
2808 dptr_close(sconn, &dptr_num); /* This frees up the saved mask */
2811 /* Set up the return parameter block */
2812 SSVAL(params,0,numentries);
2813 SSVAL(params,2,finished);
2814 SSVAL(params,4,0); /* Never an EA error */
2815 SSVAL(params,6,last_entry_off);
2817 send_trans2_replies(conn, req, params, 8, pdata, PTR_DIFF(p,pdata),
2818 max_data_bytes);
2820 return;
2823 unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
2825 E_md4hash(lp_servicename(SNUM(conn)),objid);
2826 return objid;
2829 static void samba_extended_info_version(struct smb_extended_info *extended_info)
2831 SMB_ASSERT(extended_info != NULL);
2833 extended_info->samba_magic = SAMBA_EXTENDED_INFO_MAGIC;
2834 extended_info->samba_version = ((SAMBA_VERSION_MAJOR & 0xff) << 24)
2835 | ((SAMBA_VERSION_MINOR & 0xff) << 16)
2836 | ((SAMBA_VERSION_RELEASE & 0xff) << 8);
2837 #ifdef SAMBA_VERSION_REVISION
2838 extended_info->samba_version |= (tolower(*SAMBA_VERSION_REVISION) - 'a' + 1) & 0xff;
2839 #endif
2840 extended_info->samba_subversion = 0;
2841 #ifdef SAMBA_VERSION_RC_RELEASE
2842 extended_info->samba_subversion |= (SAMBA_VERSION_RC_RELEASE & 0xff) << 24;
2843 #else
2844 #ifdef SAMBA_VERSION_PRE_RELEASE
2845 extended_info->samba_subversion |= (SAMBA_VERSION_PRE_RELEASE & 0xff) << 16;
2846 #endif
2847 #endif
2848 #ifdef SAMBA_VERSION_VENDOR_PATCH
2849 extended_info->samba_subversion |= (SAMBA_VERSION_VENDOR_PATCH & 0xffff);
2850 #endif
2851 extended_info->samba_gitcommitdate = 0;
2852 #ifdef SAMBA_VERSION_GIT_COMMIT_TIME
2853 unix_to_nt_time(&extended_info->samba_gitcommitdate, SAMBA_VERSION_GIT_COMMIT_TIME);
2854 #endif
2856 memset(extended_info->samba_version_string, 0,
2857 sizeof(extended_info->samba_version_string));
2859 snprintf (extended_info->samba_version_string,
2860 sizeof(extended_info->samba_version_string),
2861 "%s", samba_version_string());
2864 NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
2865 TALLOC_CTX *mem_ctx,
2866 uint16_t info_level,
2867 uint16_t flags2,
2868 unsigned int max_data_bytes,
2869 char **ppdata,
2870 int *ret_data_len)
2872 char *pdata, *end_data;
2873 int data_len = 0, len;
2874 const char *vname = volume_label(SNUM(conn));
2875 int snum = SNUM(conn);
2876 char *fstype = lp_fstype(SNUM(conn));
2877 uint32 additional_flags = 0;
2878 struct smb_filename *smb_fname_dot = NULL;
2879 SMB_STRUCT_STAT st;
2880 NTSTATUS status;
2882 if (IS_IPC(conn)) {
2883 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
2884 DEBUG(0,("smbd_do_qfsinfo: not an allowed "
2885 "info level (0x%x) on IPC$.\n",
2886 (unsigned int)info_level));
2887 return NT_STATUS_ACCESS_DENIED;
2891 DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level));
2893 status = create_synthetic_smb_fname(talloc_tos(), ".", NULL, NULL,
2894 &smb_fname_dot);
2895 if (!NT_STATUS_IS_OK(status)) {
2896 return status;
2899 if(SMB_VFS_STAT(conn, smb_fname_dot) != 0) {
2900 DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
2901 TALLOC_FREE(smb_fname_dot);
2902 return map_nt_error_from_unix(errno);
2905 st = smb_fname_dot->st;
2906 TALLOC_FREE(smb_fname_dot);
2908 *ppdata = (char *)SMB_REALLOC(
2909 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2910 if (*ppdata == NULL) {
2911 return NT_STATUS_NO_MEMORY;
2914 pdata = *ppdata;
2915 memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2916 end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2918 switch (info_level) {
2919 case SMB_INFO_ALLOCATION:
2921 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
2922 data_len = 18;
2923 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
2924 return map_nt_error_from_unix(errno);
2927 block_size = lp_block_size(snum);
2928 if (bsize < block_size) {
2929 uint64_t factor = block_size/bsize;
2930 bsize = block_size;
2931 dsize /= factor;
2932 dfree /= factor;
2934 if (bsize > block_size) {
2935 uint64_t factor = bsize/block_size;
2936 bsize = block_size;
2937 dsize *= factor;
2938 dfree *= factor;
2940 bytes_per_sector = 512;
2941 sectors_per_unit = bsize/bytes_per_sector;
2943 DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
2944 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
2945 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2947 SIVAL(pdata,l1_idFileSystem,st.st_ex_dev);
2948 SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
2949 SIVAL(pdata,l1_cUnit,dsize);
2950 SIVAL(pdata,l1_cUnitAvail,dfree);
2951 SSVAL(pdata,l1_cbSector,bytes_per_sector);
2952 break;
2955 case SMB_INFO_VOLUME:
2956 /* Return volume name */
2958 * Add volume serial number - hash of a combination of
2959 * the called hostname and the service name.
2961 SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(get_local_machine_name())<<16) );
2963 * Win2k3 and previous mess this up by sending a name length
2964 * one byte short. I believe only older clients (OS/2 Win9x) use
2965 * this call so try fixing this by adding a terminating null to
2966 * the pushed string. The change here was adding the STR_TERMINATE. JRA.
2968 len = srvstr_push(
2969 pdata, flags2,
2970 pdata+l2_vol_szVolLabel, vname,
2971 PTR_DIFF(end_data, pdata+l2_vol_szVolLabel),
2972 STR_NOALIGN|STR_TERMINATE);
2973 SCVAL(pdata,l2_vol_cch,len);
2974 data_len = l2_vol_szVolLabel + len;
2975 DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %d, name = %s\n",
2976 (unsigned)convert_timespec_to_time_t(st.st_ex_ctime),
2977 len, vname));
2978 break;
2980 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2981 case SMB_FS_ATTRIBUTE_INFORMATION:
2983 additional_flags = 0;
2984 #if defined(HAVE_SYS_QUOTAS)
2985 additional_flags |= FILE_VOLUME_QUOTAS;
2986 #endif
2988 if(lp_nt_acl_support(SNUM(conn))) {
2989 additional_flags |= FILE_PERSISTENT_ACLS;
2992 /* Capabilities are filled in at connection time through STATVFS call */
2993 additional_flags |= conn->fs_capabilities;
2994 additional_flags |= lp_parm_int(conn->params->service,
2995 "share", "fake_fscaps",
2998 SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
2999 FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
3000 additional_flags); /* FS ATTRIBUTES */
3002 SIVAL(pdata,4,255); /* Max filename component length */
3003 /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
3004 and will think we can't do long filenames */
3005 len = srvstr_push(pdata, flags2, pdata+12, fstype,
3006 PTR_DIFF(end_data, pdata+12),
3007 STR_UNICODE);
3008 SIVAL(pdata,8,len);
3009 data_len = 12 + len;
3010 break;
3012 case SMB_QUERY_FS_LABEL_INFO:
3013 case SMB_FS_LABEL_INFORMATION:
3014 len = srvstr_push(pdata, flags2, pdata+4, vname,
3015 PTR_DIFF(end_data, pdata+4), 0);
3016 data_len = 4 + len;
3017 SIVAL(pdata,0,len);
3018 break;
3020 case SMB_QUERY_FS_VOLUME_INFO:
3021 case SMB_FS_VOLUME_INFORMATION:
3024 * Add volume serial number - hash of a combination of
3025 * the called hostname and the service name.
3027 SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^
3028 (str_checksum(get_local_machine_name())<<16));
3030 /* Max label len is 32 characters. */
3031 len = srvstr_push(pdata, flags2, pdata+18, vname,
3032 PTR_DIFF(end_data, pdata+18),
3033 STR_UNICODE);
3034 SIVAL(pdata,12,len);
3035 data_len = 18+len;
3037 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
3038 (int)strlen(vname),vname, lp_servicename(snum)));
3039 break;
3041 case SMB_QUERY_FS_SIZE_INFO:
3042 case SMB_FS_SIZE_INFORMATION:
3044 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
3045 data_len = 24;
3046 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
3047 return map_nt_error_from_unix(errno);
3049 block_size = lp_block_size(snum);
3050 if (bsize < block_size) {
3051 uint64_t factor = block_size/bsize;
3052 bsize = block_size;
3053 dsize /= factor;
3054 dfree /= factor;
3056 if (bsize > block_size) {
3057 uint64_t factor = bsize/block_size;
3058 bsize = block_size;
3059 dsize *= factor;
3060 dfree *= factor;
3062 bytes_per_sector = 512;
3063 sectors_per_unit = bsize/bytes_per_sector;
3064 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
3065 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
3066 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
3067 SBIG_UINT(pdata,0,dsize);
3068 SBIG_UINT(pdata,8,dfree);
3069 SIVAL(pdata,16,sectors_per_unit);
3070 SIVAL(pdata,20,bytes_per_sector);
3071 break;
3074 case SMB_FS_FULL_SIZE_INFORMATION:
3076 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
3077 data_len = 32;
3078 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
3079 return map_nt_error_from_unix(errno);
3081 block_size = lp_block_size(snum);
3082 if (bsize < block_size) {
3083 uint64_t factor = block_size/bsize;
3084 bsize = block_size;
3085 dsize /= factor;
3086 dfree /= factor;
3088 if (bsize > block_size) {
3089 uint64_t factor = bsize/block_size;
3090 bsize = block_size;
3091 dsize *= factor;
3092 dfree *= factor;
3094 bytes_per_sector = 512;
3095 sectors_per_unit = bsize/bytes_per_sector;
3096 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
3097 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
3098 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
3099 SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
3100 SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
3101 SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
3102 SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
3103 SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
3104 break;
3107 case SMB_QUERY_FS_DEVICE_INFO:
3108 case SMB_FS_DEVICE_INFORMATION:
3109 data_len = 8;
3110 SIVAL(pdata,0,0); /* dev type */
3111 SIVAL(pdata,4,0); /* characteristics */
3112 break;
3114 #ifdef HAVE_SYS_QUOTAS
3115 case SMB_FS_QUOTA_INFORMATION:
3117 * what we have to send --metze:
3119 * Unknown1: 24 NULL bytes
3120 * Soft Quota Treshold: 8 bytes seems like uint64_t or so
3121 * Hard Quota Limit: 8 bytes seems like uint64_t or so
3122 * Quota Flags: 2 byte :
3123 * Unknown3: 6 NULL bytes
3125 * 48 bytes total
3127 * details for Quota Flags:
3129 * 0x0020 Log Limit: log if the user exceeds his Hard Quota
3130 * 0x0010 Log Warn: log if the user exceeds his Soft Quota
3131 * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
3132 * 0x0001 Enable Quotas: enable quota for this fs
3136 /* we need to fake up a fsp here,
3137 * because its not send in this call
3139 files_struct fsp;
3140 SMB_NTQUOTA_STRUCT quotas;
3142 ZERO_STRUCT(fsp);
3143 ZERO_STRUCT(quotas);
3145 fsp.conn = conn;
3146 fsp.fnum = -1;
3148 /* access check */
3149 if (conn->server_info->utok.uid != sec_initial_uid()) {
3150 DEBUG(0,("set_user_quota: access_denied "
3151 "service [%s] user [%s]\n",
3152 lp_servicename(SNUM(conn)),
3153 conn->server_info->unix_name));
3154 return NT_STATUS_ACCESS_DENIED;
3157 if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
3158 DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3159 return map_nt_error_from_unix(errno);
3162 data_len = 48;
3164 DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",
3165 lp_servicename(SNUM(conn))));
3167 /* Unknown1 24 NULL bytes*/
3168 SBIG_UINT(pdata,0,(uint64_t)0);
3169 SBIG_UINT(pdata,8,(uint64_t)0);
3170 SBIG_UINT(pdata,16,(uint64_t)0);
3172 /* Default Soft Quota 8 bytes */
3173 SBIG_UINT(pdata,24,quotas.softlim);
3175 /* Default Hard Quota 8 bytes */
3176 SBIG_UINT(pdata,32,quotas.hardlim);
3178 /* Quota flag 2 bytes */
3179 SSVAL(pdata,40,quotas.qflags);
3181 /* Unknown3 6 NULL bytes */
3182 SSVAL(pdata,42,0);
3183 SIVAL(pdata,44,0);
3185 break;
3187 #endif /* HAVE_SYS_QUOTAS */
3188 case SMB_FS_OBJECTID_INFORMATION:
3190 unsigned char objid[16];
3191 struct smb_extended_info extended_info;
3192 memcpy(pdata,create_volume_objectid(conn, objid),16);
3193 samba_extended_info_version (&extended_info);
3194 SIVAL(pdata,16,extended_info.samba_magic);
3195 SIVAL(pdata,20,extended_info.samba_version);
3196 SIVAL(pdata,24,extended_info.samba_subversion);
3197 SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
3198 memcpy(pdata+36,extended_info.samba_version_string,28);
3199 data_len = 64;
3200 break;
3204 * Query the version and capabilities of the CIFS UNIX extensions
3205 * in use.
3208 case SMB_QUERY_CIFS_UNIX_INFO:
3210 bool large_write = lp_min_receive_file_size() &&
3211 !srv_is_signing_active(smbd_server_conn);
3212 bool large_read = !srv_is_signing_active(smbd_server_conn);
3213 int encrypt_caps = 0;
3215 if (!lp_unix_extensions()) {
3216 return NT_STATUS_INVALID_LEVEL;
3219 switch (conn->encrypt_level) {
3220 case 0:
3221 encrypt_caps = 0;
3222 break;
3223 case 1:
3224 case Auto:
3225 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
3226 break;
3227 case Required:
3228 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
3229 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
3230 large_write = false;
3231 large_read = false;
3232 break;
3235 data_len = 12;
3236 SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
3237 SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
3239 /* We have POSIX ACLs, pathname, encryption,
3240 * large read/write, and locking capability. */
3242 SBIG_UINT(pdata,4,((uint64_t)(
3243 CIFS_UNIX_POSIX_ACLS_CAP|
3244 CIFS_UNIX_POSIX_PATHNAMES_CAP|
3245 CIFS_UNIX_FCNTL_LOCKS_CAP|
3246 CIFS_UNIX_EXTATTR_CAP|
3247 CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
3248 encrypt_caps|
3249 (large_read ? CIFS_UNIX_LARGE_READ_CAP : 0) |
3250 (large_write ?
3251 CIFS_UNIX_LARGE_WRITE_CAP : 0))));
3252 break;
3255 case SMB_QUERY_POSIX_FS_INFO:
3257 int rc;
3258 vfs_statvfs_struct svfs;
3260 if (!lp_unix_extensions()) {
3261 return NT_STATUS_INVALID_LEVEL;
3264 rc = SMB_VFS_STATVFS(conn, ".", &svfs);
3266 if (!rc) {
3267 data_len = 56;
3268 SIVAL(pdata,0,svfs.OptimalTransferSize);
3269 SIVAL(pdata,4,svfs.BlockSize);
3270 SBIG_UINT(pdata,8,svfs.TotalBlocks);
3271 SBIG_UINT(pdata,16,svfs.BlocksAvail);
3272 SBIG_UINT(pdata,24,svfs.UserBlocksAvail);
3273 SBIG_UINT(pdata,32,svfs.TotalFileNodes);
3274 SBIG_UINT(pdata,40,svfs.FreeFileNodes);
3275 SBIG_UINT(pdata,48,svfs.FsIdentifier);
3276 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
3277 #ifdef EOPNOTSUPP
3278 } else if (rc == EOPNOTSUPP) {
3279 return NT_STATUS_INVALID_LEVEL;
3280 #endif /* EOPNOTSUPP */
3281 } else {
3282 DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3283 return NT_STATUS_DOS(ERRSRV, ERRerror);
3285 break;
3288 case SMB_QUERY_POSIX_WHOAMI:
3290 uint32_t flags = 0;
3291 uint32_t sid_bytes;
3292 int i;
3294 if (!lp_unix_extensions()) {
3295 return NT_STATUS_INVALID_LEVEL;
3298 if (max_data_bytes < 40) {
3299 return NT_STATUS_BUFFER_TOO_SMALL;
3302 /* We ARE guest if global_sid_Builtin_Guests is
3303 * in our list of SIDs.
3305 if (nt_token_check_sid(&global_sid_Builtin_Guests,
3306 conn->server_info->ptok)) {
3307 flags |= SMB_WHOAMI_GUEST;
3310 /* We are NOT guest if global_sid_Authenticated_Users
3311 * is in our list of SIDs.
3313 if (nt_token_check_sid(&global_sid_Authenticated_Users,
3314 conn->server_info->ptok)) {
3315 flags &= ~SMB_WHOAMI_GUEST;
3318 /* NOTE: 8 bytes for UID/GID, irrespective of native
3319 * platform size. This matches
3320 * SMB_QUERY_FILE_UNIX_BASIC and friends.
3322 data_len = 4 /* flags */
3323 + 4 /* flag mask */
3324 + 8 /* uid */
3325 + 8 /* gid */
3326 + 4 /* ngroups */
3327 + 4 /* num_sids */
3328 + 4 /* SID bytes */
3329 + 4 /* pad/reserved */
3330 + (conn->server_info->utok.ngroups * 8)
3331 /* groups list */
3332 + (conn->server_info->ptok->num_sids *
3333 SID_MAX_SIZE)
3334 /* SID list */;
3336 SIVAL(pdata, 0, flags);
3337 SIVAL(pdata, 4, SMB_WHOAMI_MASK);
3338 SBIG_UINT(pdata, 8,
3339 (uint64_t)conn->server_info->utok.uid);
3340 SBIG_UINT(pdata, 16,
3341 (uint64_t)conn->server_info->utok.gid);
3344 if (data_len >= max_data_bytes) {
3345 /* Potential overflow, skip the GIDs and SIDs. */
3347 SIVAL(pdata, 24, 0); /* num_groups */
3348 SIVAL(pdata, 28, 0); /* num_sids */
3349 SIVAL(pdata, 32, 0); /* num_sid_bytes */
3350 SIVAL(pdata, 36, 0); /* reserved */
3352 data_len = 40;
3353 break;
3356 SIVAL(pdata, 24, conn->server_info->utok.ngroups);
3357 SIVAL(pdata, 28, conn->server_info->num_sids);
3359 /* We walk the SID list twice, but this call is fairly
3360 * infrequent, and I don't expect that it's performance
3361 * sensitive -- jpeach
3363 for (i = 0, sid_bytes = 0;
3364 i < conn->server_info->ptok->num_sids; ++i) {
3365 sid_bytes += ndr_size_dom_sid(
3366 &conn->server_info->ptok->user_sids[i],
3367 NULL,
3371 /* SID list byte count */
3372 SIVAL(pdata, 32, sid_bytes);
3374 /* 4 bytes pad/reserved - must be zero */
3375 SIVAL(pdata, 36, 0);
3376 data_len = 40;
3378 /* GID list */
3379 for (i = 0; i < conn->server_info->utok.ngroups; ++i) {
3380 SBIG_UINT(pdata, data_len,
3381 (uint64_t)conn->server_info->utok.groups[i]);
3382 data_len += 8;
3385 /* SID list */
3386 for (i = 0;
3387 i < conn->server_info->ptok->num_sids; ++i) {
3388 int sid_len = ndr_size_dom_sid(
3389 &conn->server_info->ptok->user_sids[i],
3390 NULL,
3393 sid_linearize(pdata + data_len, sid_len,
3394 &conn->server_info->ptok->user_sids[i]);
3395 data_len += sid_len;
3398 break;
3401 case SMB_MAC_QUERY_FS_INFO:
3403 * Thursby MAC extension... ONLY on NTFS filesystems
3404 * once we do streams then we don't need this
3406 if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
3407 data_len = 88;
3408 SIVAL(pdata,84,0x100); /* Don't support mac... */
3409 break;
3411 /* drop through */
3412 default:
3413 return NT_STATUS_INVALID_LEVEL;
3416 *ret_data_len = data_len;
3417 return NT_STATUS_OK;
3420 /****************************************************************************
3421 Reply to a TRANS2_QFSINFO (query filesystem info).
3422 ****************************************************************************/
3424 static void call_trans2qfsinfo(connection_struct *conn,
3425 struct smb_request *req,
3426 char **pparams, int total_params,
3427 char **ppdata, int total_data,
3428 unsigned int max_data_bytes)
3430 char *params = *pparams;
3431 uint16_t info_level;
3432 int data_len = 0;
3433 NTSTATUS status;
3435 if (total_params < 2) {
3436 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3437 return;
3440 info_level = SVAL(params,0);
3442 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
3443 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
3444 DEBUG(0,("call_trans2qfsinfo: encryption required "
3445 "and info level 0x%x sent.\n",
3446 (unsigned int)info_level));
3447 exit_server_cleanly("encryption required "
3448 "on connection");
3449 return;
3453 DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
3455 status = smbd_do_qfsinfo(conn, req,
3456 info_level,
3457 req->flags2,
3458 max_data_bytes,
3459 ppdata, &data_len);
3460 if (!NT_STATUS_IS_OK(status)) {
3461 reply_nterror(req, status);
3462 return;
3465 send_trans2_replies(conn, req, params, 0, *ppdata, data_len,
3466 max_data_bytes);
3468 DEBUG( 4, ( "%s info_level = %d\n",
3469 smb_fn_name(req->cmd), info_level) );
3471 return;
3474 /****************************************************************************
3475 Reply to a TRANS2_SETFSINFO (set filesystem info).
3476 ****************************************************************************/
3478 static void call_trans2setfsinfo(connection_struct *conn,
3479 struct smb_request *req,
3480 char **pparams, int total_params,
3481 char **ppdata, int total_data,
3482 unsigned int max_data_bytes)
3484 char *pdata = *ppdata;
3485 char *params = *pparams;
3486 uint16 info_level;
3488 DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",lp_servicename(SNUM(conn))));
3490 /* */
3491 if (total_params < 4) {
3492 DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
3493 total_params));
3494 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3495 return;
3498 info_level = SVAL(params,2);
3500 if (IS_IPC(conn)) {
3501 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION &&
3502 info_level != SMB_SET_CIFS_UNIX_INFO) {
3503 DEBUG(0,("call_trans2setfsinfo: not an allowed "
3504 "info level (0x%x) on IPC$.\n",
3505 (unsigned int)info_level));
3506 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3507 return;
3511 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
3512 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION) {
3513 DEBUG(0,("call_trans2setfsinfo: encryption required "
3514 "and info level 0x%x sent.\n",
3515 (unsigned int)info_level));
3516 exit_server_cleanly("encryption required "
3517 "on connection");
3518 return;
3522 switch(info_level) {
3523 case SMB_SET_CIFS_UNIX_INFO:
3525 uint16 client_unix_major;
3526 uint16 client_unix_minor;
3527 uint32 client_unix_cap_low;
3528 uint32 client_unix_cap_high;
3530 if (!lp_unix_extensions()) {
3531 reply_nterror(req,
3532 NT_STATUS_INVALID_LEVEL);
3533 return;
3536 /* There should be 12 bytes of capabilities set. */
3537 if (total_data < 8) {
3538 reply_nterror(
3539 req,
3540 NT_STATUS_INVALID_PARAMETER);
3541 return;
3543 client_unix_major = SVAL(pdata,0);
3544 client_unix_minor = SVAL(pdata,2);
3545 client_unix_cap_low = IVAL(pdata,4);
3546 client_unix_cap_high = IVAL(pdata,8);
3547 /* Just print these values for now. */
3548 DEBUG(10,("call_trans2setfsinfo: set unix info. major = %u, minor = %u \
3549 cap_low = 0x%x, cap_high = 0x%x\n",
3550 (unsigned int)client_unix_major,
3551 (unsigned int)client_unix_minor,
3552 (unsigned int)client_unix_cap_low,
3553 (unsigned int)client_unix_cap_high ));
3555 /* Here is where we must switch to posix pathname processing... */
3556 if (client_unix_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3557 lp_set_posix_pathnames();
3558 mangle_change_to_posix();
3561 if ((client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) &&
3562 !(client_unix_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) {
3563 /* Client that knows how to do posix locks,
3564 * but not posix open/mkdir operations. Set a
3565 * default type for read/write checks. */
3567 lp_set_posix_default_cifsx_readwrite_locktype(POSIX_LOCK);
3570 break;
3573 case SMB_REQUEST_TRANSPORT_ENCRYPTION:
3575 NTSTATUS status;
3576 size_t param_len = 0;
3577 size_t data_len = total_data;
3579 if (!lp_unix_extensions()) {
3580 reply_nterror(
3581 req,
3582 NT_STATUS_INVALID_LEVEL);
3583 return;
3586 if (lp_smb_encrypt(SNUM(conn)) == false) {
3587 reply_nterror(
3588 req,
3589 NT_STATUS_NOT_SUPPORTED);
3590 return;
3593 DEBUG( 4,("call_trans2setfsinfo: "
3594 "request transport encryption.\n"));
3596 status = srv_request_encryption_setup(conn,
3597 (unsigned char **)ppdata,
3598 &data_len,
3599 (unsigned char **)pparams,
3600 &param_len);
3602 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
3603 !NT_STATUS_IS_OK(status)) {
3604 reply_nterror(req, status);
3605 return;
3608 send_trans2_replies(conn, req,
3609 *pparams,
3610 param_len,
3611 *ppdata,
3612 data_len,
3613 max_data_bytes);
3615 if (NT_STATUS_IS_OK(status)) {
3616 /* Server-side transport
3617 * encryption is now *on*. */
3618 status = srv_encryption_start(conn);
3619 if (!NT_STATUS_IS_OK(status)) {
3620 exit_server_cleanly(
3621 "Failure in setting "
3622 "up encrypted transport");
3625 return;
3628 case SMB_FS_QUOTA_INFORMATION:
3630 files_struct *fsp = NULL;
3631 SMB_NTQUOTA_STRUCT quotas;
3633 ZERO_STRUCT(quotas);
3635 /* access check */
3636 if ((conn->server_info->utok.uid != sec_initial_uid())
3637 ||!CAN_WRITE(conn)) {
3638 DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
3639 lp_servicename(SNUM(conn)),
3640 conn->server_info->unix_name));
3641 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3642 return;
3645 /* note: normaly there're 48 bytes,
3646 * but we didn't use the last 6 bytes for now
3647 * --metze
3649 fsp = file_fsp(req, SVAL(params,0));
3651 if (!check_fsp_ntquota_handle(conn, req,
3652 fsp)) {
3653 DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
3654 reply_nterror(
3655 req, NT_STATUS_INVALID_HANDLE);
3656 return;
3659 if (total_data < 42) {
3660 DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n",
3661 total_data));
3662 reply_nterror(
3663 req,
3664 NT_STATUS_INVALID_PARAMETER);
3665 return;
3668 /* unknown_1 24 NULL bytes in pdata*/
3670 /* the soft quotas 8 bytes (uint64_t)*/
3671 quotas.softlim = (uint64_t)IVAL(pdata,24);
3672 #ifdef LARGE_SMB_OFF_T
3673 quotas.softlim |= (((uint64_t)IVAL(pdata,28)) << 32);
3674 #else /* LARGE_SMB_OFF_T */
3675 if ((IVAL(pdata,28) != 0)&&
3676 ((quotas.softlim != 0xFFFFFFFF)||
3677 (IVAL(pdata,28)!=0xFFFFFFFF))) {
3678 /* more than 32 bits? */
3679 reply_nterror(
3680 req,
3681 NT_STATUS_INVALID_PARAMETER);
3682 return;
3684 #endif /* LARGE_SMB_OFF_T */
3686 /* the hard quotas 8 bytes (uint64_t)*/
3687 quotas.hardlim = (uint64_t)IVAL(pdata,32);
3688 #ifdef LARGE_SMB_OFF_T
3689 quotas.hardlim |= (((uint64_t)IVAL(pdata,36)) << 32);
3690 #else /* LARGE_SMB_OFF_T */
3691 if ((IVAL(pdata,36) != 0)&&
3692 ((quotas.hardlim != 0xFFFFFFFF)||
3693 (IVAL(pdata,36)!=0xFFFFFFFF))) {
3694 /* more than 32 bits? */
3695 reply_nterror(
3696 req,
3697 NT_STATUS_INVALID_PARAMETER);
3698 return;
3700 #endif /* LARGE_SMB_OFF_T */
3702 /* quota_flags 2 bytes **/
3703 quotas.qflags = SVAL(pdata,40);
3705 /* unknown_2 6 NULL bytes follow*/
3707 /* now set the quotas */
3708 if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
3709 DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3710 reply_nterror(req, map_nt_error_from_unix(errno));
3711 return;
3714 break;
3716 default:
3717 DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
3718 info_level));
3719 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
3720 return;
3721 break;
3725 * sending this reply works fine,
3726 * but I'm not sure it's the same
3727 * like windows do...
3728 * --metze
3730 reply_outbuf(req, 10, 0);
3733 #if defined(HAVE_POSIX_ACLS)
3734 /****************************************************************************
3735 Utility function to count the number of entries in a POSIX acl.
3736 ****************************************************************************/
3738 static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
3740 unsigned int ace_count = 0;
3741 int entry_id = SMB_ACL_FIRST_ENTRY;
3742 SMB_ACL_ENTRY_T entry;
3744 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
3745 /* get_next... */
3746 if (entry_id == SMB_ACL_FIRST_ENTRY) {
3747 entry_id = SMB_ACL_NEXT_ENTRY;
3749 ace_count++;
3751 return ace_count;
3754 /****************************************************************************
3755 Utility function to marshall a POSIX acl into wire format.
3756 ****************************************************************************/
3758 static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
3760 int entry_id = SMB_ACL_FIRST_ENTRY;
3761 SMB_ACL_ENTRY_T entry;
3763 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
3764 SMB_ACL_TAG_T tagtype;
3765 SMB_ACL_PERMSET_T permset;
3766 unsigned char perms = 0;
3767 unsigned int own_grp;
3769 /* get_next... */
3770 if (entry_id == SMB_ACL_FIRST_ENTRY) {
3771 entry_id = SMB_ACL_NEXT_ENTRY;
3774 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3775 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
3776 return False;
3779 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3780 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
3781 return False;
3784 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
3785 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
3786 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
3788 SCVAL(pdata,1,perms);
3790 switch (tagtype) {
3791 case SMB_ACL_USER_OBJ:
3792 SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
3793 own_grp = (unsigned int)pst->st_ex_uid;
3794 SIVAL(pdata,2,own_grp);
3795 SIVAL(pdata,6,0);
3796 break;
3797 case SMB_ACL_USER:
3799 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3800 if (!puid) {
3801 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
3802 return False;
3804 own_grp = (unsigned int)*puid;
3805 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
3806 SCVAL(pdata,0,SMB_POSIX_ACL_USER);
3807 SIVAL(pdata,2,own_grp);
3808 SIVAL(pdata,6,0);
3809 break;
3811 case SMB_ACL_GROUP_OBJ:
3812 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
3813 own_grp = (unsigned int)pst->st_ex_gid;
3814 SIVAL(pdata,2,own_grp);
3815 SIVAL(pdata,6,0);
3816 break;
3817 case SMB_ACL_GROUP:
3819 gid_t *pgid= (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3820 if (!pgid) {
3821 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
3822 return False;
3824 own_grp = (unsigned int)*pgid;
3825 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
3826 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
3827 SIVAL(pdata,2,own_grp);
3828 SIVAL(pdata,6,0);
3829 break;
3831 case SMB_ACL_MASK:
3832 SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
3833 SIVAL(pdata,2,0xFFFFFFFF);
3834 SIVAL(pdata,6,0xFFFFFFFF);
3835 break;
3836 case SMB_ACL_OTHER:
3837 SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
3838 SIVAL(pdata,2,0xFFFFFFFF);
3839 SIVAL(pdata,6,0xFFFFFFFF);
3840 break;
3841 default:
3842 DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
3843 return False;
3845 pdata += SMB_POSIX_ACL_ENTRY_SIZE;
3848 return True;
3850 #endif
3852 /****************************************************************************
3853 Store the FILE_UNIX_BASIC info.
3854 ****************************************************************************/
3856 static char *store_file_unix_basic(connection_struct *conn,
3857 char *pdata,
3858 files_struct *fsp,
3859 const SMB_STRUCT_STAT *psbuf)
3861 DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
3862 DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode));
3864 SOFF_T(pdata,0,get_file_size_stat(psbuf)); /* File size 64 Bit */
3865 pdata += 8;
3867 SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
3868 pdata += 8;
3870 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, psbuf->st_ex_ctime); /* Change Time 64 Bit */
3871 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, psbuf->st_ex_atime); /* Last access time 64 Bit */
3872 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, psbuf->st_ex_mtime); /* Last modification time 64 Bit */
3873 pdata += 24;
3875 SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */
3876 SIVAL(pdata,4,0);
3877 pdata += 8;
3879 SIVAL(pdata,0,psbuf->st_ex_gid); /* group id of owner */
3880 SIVAL(pdata,4,0);
3881 pdata += 8;
3883 SIVAL(pdata,0,unix_filetype(psbuf->st_ex_mode));
3884 pdata += 4;
3886 SIVAL(pdata,0,unix_dev_major(psbuf->st_ex_rdev)); /* Major device number if type is device */
3887 SIVAL(pdata,4,0);
3888 pdata += 8;
3890 SIVAL(pdata,0,unix_dev_minor(psbuf->st_ex_rdev)); /* Minor device number if type is device */
3891 SIVAL(pdata,4,0);
3892 pdata += 8;
3894 SINO_T_VAL(pdata,0,(SMB_INO_T)psbuf->st_ex_ino); /* inode number */
3895 pdata += 8;
3897 SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode)); /* Standard UNIX file permissions */
3898 SIVAL(pdata,4,0);
3899 pdata += 8;
3901 SIVAL(pdata,0,psbuf->st_ex_nlink); /* number of hard links */
3902 SIVAL(pdata,4,0);
3903 pdata += 8;
3905 return pdata;
3908 /* Forward and reverse mappings from the UNIX_INFO2 file flags field and
3909 * the chflags(2) (or equivalent) flags.
3911 * XXX: this really should be behind the VFS interface. To do this, we would
3912 * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field.
3913 * Each VFS module could then implement its own mapping as appropriate for the
3914 * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS.
3916 static const struct {unsigned stat_fflag; unsigned smb_fflag;}
3917 info2_flags_map[] =
3919 #ifdef UF_NODUMP
3920 { UF_NODUMP, EXT_DO_NOT_BACKUP },
3921 #endif
3923 #ifdef UF_IMMUTABLE
3924 { UF_IMMUTABLE, EXT_IMMUTABLE },
3925 #endif
3927 #ifdef UF_APPEND
3928 { UF_APPEND, EXT_OPEN_APPEND_ONLY },
3929 #endif
3931 #ifdef UF_HIDDEN
3932 { UF_HIDDEN, EXT_HIDDEN },
3933 #endif
3935 /* Do not remove. We need to guarantee that this array has at least one
3936 * entry to build on HP-UX.
3938 { 0, 0 }
3942 static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
3943 uint32 *smb_fflags, uint32 *smb_fmask)
3945 int i;
3947 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3948 *smb_fmask |= info2_flags_map[i].smb_fflag;
3949 if (psbuf->st_ex_flags & info2_flags_map[i].stat_fflag) {
3950 *smb_fflags |= info2_flags_map[i].smb_fflag;
3955 static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
3956 const uint32 smb_fflags,
3957 const uint32 smb_fmask,
3958 int *stat_fflags)
3960 uint32 max_fmask = 0;
3961 int i;
3963 *stat_fflags = psbuf->st_ex_flags;
3965 /* For each flags requested in smb_fmask, check the state of the
3966 * corresponding flag in smb_fflags and set or clear the matching
3967 * stat flag.
3970 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3971 max_fmask |= info2_flags_map[i].smb_fflag;
3972 if (smb_fmask & info2_flags_map[i].smb_fflag) {
3973 if (smb_fflags & info2_flags_map[i].smb_fflag) {
3974 *stat_fflags |= info2_flags_map[i].stat_fflag;
3975 } else {
3976 *stat_fflags &= ~info2_flags_map[i].stat_fflag;
3981 /* If smb_fmask is asking to set any bits that are not supported by
3982 * our flag mappings, we should fail.
3984 if ((smb_fmask & max_fmask) != smb_fmask) {
3985 return False;
3988 return True;
3992 /* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition
3993 * of file flags and birth (create) time.
3995 static char *store_file_unix_basic_info2(connection_struct *conn,
3996 char *pdata,
3997 files_struct *fsp,
3998 const SMB_STRUCT_STAT *psbuf)
4000 uint32 file_flags = 0;
4001 uint32 flags_mask = 0;
4003 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
4005 /* Create (birth) time 64 bit */
4006 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, psbuf->st_ex_btime);
4007 pdata += 8;
4009 map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
4010 SIVAL(pdata, 0, file_flags); /* flags */
4011 SIVAL(pdata, 4, flags_mask); /* mask */
4012 pdata += 8;
4014 return pdata;
4017 static NTSTATUS marshall_stream_info(unsigned int num_streams,
4018 const struct stream_struct *streams,
4019 char *data,
4020 unsigned int max_data_bytes,
4021 unsigned int *data_size)
4023 unsigned int i;
4024 unsigned int ofs = 0;
4026 for (i = 0; i < num_streams && ofs <= max_data_bytes; i++) {
4027 unsigned int next_offset;
4028 size_t namelen;
4029 smb_ucs2_t *namebuf;
4031 if (!push_ucs2_talloc(talloc_tos(), &namebuf,
4032 streams[i].name, &namelen) ||
4033 namelen <= 2)
4035 return NT_STATUS_INVALID_PARAMETER;
4039 * name_buf is now null-terminated, we need to marshall as not
4040 * terminated
4043 namelen -= 2;
4045 SIVAL(data, ofs+4, namelen);
4046 SOFF_T(data, ofs+8, streams[i].size);
4047 SOFF_T(data, ofs+16, streams[i].alloc_size);
4048 memcpy(data+ofs+24, namebuf, namelen);
4049 TALLOC_FREE(namebuf);
4051 next_offset = ofs + 24 + namelen;
4053 if (i == num_streams-1) {
4054 SIVAL(data, ofs, 0);
4056 else {
4057 unsigned int align = ndr_align_size(next_offset, 8);
4059 memset(data+next_offset, 0, align);
4060 next_offset += align;
4062 SIVAL(data, ofs, next_offset - ofs);
4063 ofs = next_offset;
4066 ofs = next_offset;
4069 *data_size = ofs;
4071 return NT_STATUS_OK;
4074 /****************************************************************************
4075 Reply to a TRANSACT2_QFILEINFO on a PIPE !
4076 ****************************************************************************/
4078 static void call_trans2qpipeinfo(connection_struct *conn,
4079 struct smb_request *req,
4080 unsigned int tran_call,
4081 char **pparams, int total_params,
4082 char **ppdata, int total_data,
4083 unsigned int max_data_bytes)
4085 char *params = *pparams;
4086 char *pdata = *ppdata;
4087 unsigned int data_size = 0;
4088 unsigned int param_size = 2;
4089 uint16 info_level;
4090 files_struct *fsp;
4092 if (!params) {
4093 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4094 return;
4097 if (total_params < 4) {
4098 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4099 return;
4102 fsp = file_fsp(req, SVAL(params,0));
4103 if (!fsp_is_np(fsp)) {
4104 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4105 return;
4108 info_level = SVAL(params,2);
4110 *pparams = (char *)SMB_REALLOC(*pparams,2);
4111 if (*pparams == NULL) {
4112 reply_nterror(req, NT_STATUS_NO_MEMORY);
4113 return;
4115 params = *pparams;
4116 SSVAL(params,0,0);
4117 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
4118 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
4119 if (*ppdata == NULL ) {
4120 reply_nterror(req, NT_STATUS_NO_MEMORY);
4121 return;
4123 pdata = *ppdata;
4125 switch (info_level) {
4126 case SMB_FILE_STANDARD_INFORMATION:
4127 memset(pdata,0,24);
4128 SOFF_T(pdata,0,4096LL);
4129 SIVAL(pdata,16,1);
4130 SIVAL(pdata,20,1);
4131 data_size = 24;
4132 break;
4134 default:
4135 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4136 return;
4139 send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
4140 max_data_bytes);
4142 return;
4145 NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
4146 TALLOC_CTX *mem_ctx,
4147 uint16_t info_level,
4148 files_struct *fsp,
4149 struct smb_filename *smb_fname,
4150 bool delete_pending,
4151 struct timespec write_time_ts,
4152 bool ms_dfs_link,
4153 struct ea_list *ea_list,
4154 int lock_data_count,
4155 char *lock_data,
4156 uint16_t flags2,
4157 unsigned int max_data_bytes,
4158 char **ppdata,
4159 unsigned int *pdata_size)
4161 char *pdata = *ppdata;
4162 char *dstart, *dend;
4163 unsigned int data_size;
4164 struct timespec create_time_ts, mtime_ts, atime_ts, ctime_ts;
4165 time_t create_time, mtime, atime, c_time;
4166 SMB_STRUCT_STAT *psbuf = &smb_fname->st;
4167 char *p;
4168 char *base_name;
4169 char *dos_fname;
4170 int mode;
4171 int nlink;
4172 NTSTATUS status;
4173 uint64_t file_size = 0;
4174 uint64_t pos = 0;
4175 uint64_t allocation_size = 0;
4176 uint64_t file_index = 0;
4177 uint32_t access_mask = 0;
4179 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
4180 return NT_STATUS_INVALID_LEVEL;
4183 DEBUG(5,("smbd_do_qfilepathinfo: %s (fnum = %d) level=%d max_data=%u\n",
4184 smb_fname_str_dbg(smb_fname), fsp ? fsp->fnum : -1,
4185 info_level, max_data_bytes));
4187 if (ms_dfs_link) {
4188 mode = dos_mode_msdfs(conn, smb_fname);
4189 } else {
4190 mode = dos_mode(conn, smb_fname);
4192 if (!mode)
4193 mode = FILE_ATTRIBUTE_NORMAL;
4195 nlink = psbuf->st_ex_nlink;
4197 if (nlink && (mode&aDIR)) {
4198 nlink = 1;
4201 if ((nlink > 0) && delete_pending) {
4202 nlink -= 1;
4205 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
4206 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
4207 if (*ppdata == NULL) {
4208 return NT_STATUS_NO_MEMORY;
4210 pdata = *ppdata;
4211 dstart = pdata;
4212 dend = dstart + data_size - 1;
4214 if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) {
4215 update_stat_ex_mtime(psbuf, write_time_ts);
4218 create_time_ts = get_create_timespec(conn, fsp, smb_fname);
4219 mtime_ts = psbuf->st_ex_mtime;
4220 atime_ts = psbuf->st_ex_atime;
4221 ctime_ts = get_change_timespec(conn, fsp, smb_fname);
4223 if (lp_dos_filetime_resolution(SNUM(conn))) {
4224 dos_filetime_timespec(&create_time_ts);
4225 dos_filetime_timespec(&mtime_ts);
4226 dos_filetime_timespec(&atime_ts);
4227 dos_filetime_timespec(&ctime_ts);
4230 create_time = convert_timespec_to_time_t(create_time_ts);
4231 mtime = convert_timespec_to_time_t(mtime_ts);
4232 atime = convert_timespec_to_time_t(atime_ts);
4233 c_time = convert_timespec_to_time_t(ctime_ts);
4235 p = strrchr_m(smb_fname->base_name,'/');
4236 if (!p)
4237 base_name = smb_fname->base_name;
4238 else
4239 base_name = p+1;
4241 /* NT expects the name to be in an exact form of the *full*
4242 filename. See the trans2 torture test */
4243 if (ISDOT(base_name)) {
4244 dos_fname = talloc_strdup(mem_ctx, "\\");
4245 if (!dos_fname) {
4246 return NT_STATUS_NO_MEMORY;
4248 } else {
4249 dos_fname = talloc_asprintf(mem_ctx,
4250 "\\%s",
4251 smb_fname->base_name);
4252 if (!dos_fname) {
4253 return NT_STATUS_NO_MEMORY;
4255 if (is_ntfs_stream_smb_fname(smb_fname)) {
4256 dos_fname = talloc_asprintf(dos_fname, "%s",
4257 smb_fname->stream_name);
4258 if (!dos_fname) {
4259 return NT_STATUS_NO_MEMORY;
4263 string_replace(dos_fname, '/', '\\');
4266 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, psbuf);
4268 if (!fsp) {
4269 /* Do we have this path open ? */
4270 files_struct *fsp1;
4271 struct file_id fileid = vfs_file_id_from_sbuf(conn, psbuf);
4272 fsp1 = file_find_di_first(fileid);
4273 if (fsp1 && fsp1->initial_allocation_size) {
4274 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, psbuf);
4278 if (!(mode & aDIR)) {
4279 file_size = get_file_size_stat(psbuf);
4282 if (fsp) {
4283 pos = fsp->fh->position_information;
4286 if (fsp) {
4287 access_mask = fsp->access_mask;
4288 } else {
4289 /* GENERIC_EXECUTE mapping from Windows */
4290 access_mask = 0x12019F;
4293 /* This should be an index number - looks like
4294 dev/ino to me :-)
4296 I think this causes us to fail the IFSKIT
4297 BasicFileInformationTest. -tpot */
4298 file_index = ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */
4299 file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */
4301 switch (info_level) {
4302 case SMB_INFO_STANDARD:
4303 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
4304 data_size = 22;
4305 srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
4306 srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
4307 srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
4308 SIVAL(pdata,l1_cbFile,(uint32)file_size);
4309 SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
4310 SSVAL(pdata,l1_attrFile,mode);
4311 break;
4313 case SMB_INFO_QUERY_EA_SIZE:
4315 unsigned int ea_size =
4316 estimate_ea_size(conn, fsp,
4317 smb_fname->base_name);
4318 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
4319 data_size = 26;
4320 srv_put_dos_date2(pdata,0,create_time);
4321 srv_put_dos_date2(pdata,4,atime);
4322 srv_put_dos_date2(pdata,8,mtime); /* write time */
4323 SIVAL(pdata,12,(uint32)file_size);
4324 SIVAL(pdata,16,(uint32)allocation_size);
4325 SSVAL(pdata,20,mode);
4326 SIVAL(pdata,22,ea_size);
4327 break;
4330 case SMB_INFO_IS_NAME_VALID:
4331 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
4332 if (fsp) {
4333 /* os/2 needs this ? really ?*/
4334 return NT_STATUS_DOS(ERRDOS, ERRbadfunc);
4336 /* This is only reached for qpathinfo */
4337 data_size = 0;
4338 break;
4340 case SMB_INFO_QUERY_EAS_FROM_LIST:
4342 size_t total_ea_len = 0;
4343 struct ea_list *ea_file_list = NULL;
4345 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
4347 ea_file_list =
4348 get_ea_list_from_file(mem_ctx, conn, fsp,
4349 smb_fname->base_name,
4350 &total_ea_len);
4351 ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
4353 if (!ea_list || (total_ea_len > data_size)) {
4354 data_size = 4;
4355 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
4356 break;
4359 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
4360 break;
4363 case SMB_INFO_QUERY_ALL_EAS:
4365 /* We have data_size bytes to put EA's into. */
4366 size_t total_ea_len = 0;
4368 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
4370 ea_list = get_ea_list_from_file(mem_ctx, conn, fsp,
4371 smb_fname->base_name,
4372 &total_ea_len);
4373 if (!ea_list || (total_ea_len > data_size)) {
4374 data_size = 4;
4375 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
4376 break;
4379 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
4380 break;
4383 case 0xFF0F:/*SMB2_INFO_QUERY_ALL_EAS*/
4385 /* This is FileFullEaInformation - 0xF which maps to
4386 * 1015 (decimal) in smbd_do_setfilepathinfo. */
4388 /* We have data_size bytes to put EA's into. */
4389 size_t total_ea_len = 0;
4390 struct ea_list *ea_file_list = NULL;
4392 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n"));
4394 /*TODO: add filtering and index handling */
4396 ea_file_list =
4397 get_ea_list_from_file(mem_ctx, conn, fsp,
4398 smb_fname->base_name,
4399 &total_ea_len);
4400 if (!ea_file_list) {
4401 return NT_STATUS_NO_EAS_ON_FILE;
4404 status = fill_ea_chained_buffer(mem_ctx,
4405 pdata,
4406 data_size,
4407 &data_size,
4408 conn, ea_file_list);
4409 if (!NT_STATUS_IS_OK(status)) {
4410 return status;
4412 break;
4415 case SMB_FILE_BASIC_INFORMATION:
4416 case SMB_QUERY_FILE_BASIC_INFO:
4418 if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
4419 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
4420 data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
4421 } else {
4422 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
4423 data_size = 40;
4424 SIVAL(pdata,36,0);
4426 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
4427 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
4428 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
4429 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
4430 SIVAL(pdata,32,mode);
4432 DEBUG(5,("SMB_QFBI - "));
4433 DEBUG(5,("create: %s ", ctime(&create_time)));
4434 DEBUG(5,("access: %s ", ctime(&atime)));
4435 DEBUG(5,("write: %s ", ctime(&mtime)));
4436 DEBUG(5,("change: %s ", ctime(&c_time)));
4437 DEBUG(5,("mode: %x\n", mode));
4438 break;
4440 case SMB_FILE_STANDARD_INFORMATION:
4441 case SMB_QUERY_FILE_STANDARD_INFO:
4443 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
4444 data_size = 24;
4445 SOFF_T(pdata,0,allocation_size);
4446 SOFF_T(pdata,8,file_size);
4447 SIVAL(pdata,16,nlink);
4448 SCVAL(pdata,20,delete_pending?1:0);
4449 SCVAL(pdata,21,(mode&aDIR)?1:0);
4450 SSVAL(pdata,22,0); /* Padding. */
4451 break;
4453 case SMB_FILE_EA_INFORMATION:
4454 case SMB_QUERY_FILE_EA_INFO:
4456 unsigned int ea_size =
4457 estimate_ea_size(conn, fsp, smb_fname->base_name);
4458 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
4459 data_size = 4;
4460 SIVAL(pdata,0,ea_size);
4461 break;
4464 /* Get the 8.3 name - used if NT SMB was negotiated. */
4465 case SMB_QUERY_FILE_ALT_NAME_INFO:
4466 case SMB_FILE_ALTERNATE_NAME_INFORMATION:
4468 int len;
4469 char mangled_name[13];
4470 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
4471 if (!name_to_8_3(base_name,mangled_name,
4472 True,conn->params)) {
4473 return NT_STATUS_NO_MEMORY;
4475 len = srvstr_push(dstart, flags2,
4476 pdata+4, mangled_name,
4477 PTR_DIFF(dend, pdata+4),
4478 STR_UNICODE);
4479 data_size = 4 + len;
4480 SIVAL(pdata,0,len);
4481 break;
4484 case SMB_QUERY_FILE_NAME_INFO:
4486 int len;
4488 this must be *exactly* right for ACLs on mapped drives to work
4490 len = srvstr_push(dstart, flags2,
4491 pdata+4, dos_fname,
4492 PTR_DIFF(dend, pdata+4),
4493 STR_UNICODE);
4494 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
4495 data_size = 4 + len;
4496 SIVAL(pdata,0,len);
4497 break;
4500 case SMB_FILE_ALLOCATION_INFORMATION:
4501 case SMB_QUERY_FILE_ALLOCATION_INFO:
4502 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
4503 data_size = 8;
4504 SOFF_T(pdata,0,allocation_size);
4505 break;
4507 case SMB_FILE_END_OF_FILE_INFORMATION:
4508 case SMB_QUERY_FILE_END_OF_FILEINFO:
4509 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
4510 data_size = 8;
4511 SOFF_T(pdata,0,file_size);
4512 break;
4514 case SMB_QUERY_FILE_ALL_INFO:
4515 case SMB_FILE_ALL_INFORMATION:
4517 int len;
4518 unsigned int ea_size =
4519 estimate_ea_size(conn, fsp, smb_fname->base_name);
4520 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
4521 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
4522 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
4523 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
4524 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
4525 SIVAL(pdata,32,mode);
4526 SIVAL(pdata,36,0); /* padding. */
4527 pdata += 40;
4528 SOFF_T(pdata,0,allocation_size);
4529 SOFF_T(pdata,8,file_size);
4530 SIVAL(pdata,16,nlink);
4531 SCVAL(pdata,20,delete_pending);
4532 SCVAL(pdata,21,(mode&aDIR)?1:0);
4533 SSVAL(pdata,22,0);
4534 pdata += 24;
4535 SIVAL(pdata,0,ea_size);
4536 pdata += 4; /* EA info */
4537 len = srvstr_push(dstart, flags2,
4538 pdata+4, dos_fname,
4539 PTR_DIFF(dend, pdata+4),
4540 STR_UNICODE);
4541 SIVAL(pdata,0,len);
4542 pdata += 4 + len;
4543 data_size = PTR_DIFF(pdata,(*ppdata));
4544 break;
4547 case 0xFF12:/*SMB2_FILE_ALL_INFORMATION*/
4549 int len;
4550 unsigned int ea_size =
4551 estimate_ea_size(conn, fsp, smb_fname->base_name);
4552 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
4553 put_long_date_timespec(conn->ts_res,pdata+0x00,create_time_ts);
4554 put_long_date_timespec(conn->ts_res,pdata+0x08,atime_ts);
4555 put_long_date_timespec(conn->ts_res,pdata+0x10,mtime_ts); /* write time */
4556 put_long_date_timespec(conn->ts_res,pdata+0x18,ctime_ts); /* change time */
4557 SIVAL(pdata, 0x20, mode);
4558 SIVAL(pdata, 0x24, 0); /* padding. */
4559 SBVAL(pdata, 0x28, allocation_size);
4560 SBVAL(pdata, 0x30, file_size);
4561 SIVAL(pdata, 0x38, nlink);
4562 SCVAL(pdata, 0x3C, delete_pending);
4563 SCVAL(pdata, 0x3D, (mode&aDIR)?1:0);
4564 SSVAL(pdata, 0x3E, 0); /* padding */
4565 SBVAL(pdata, 0x40, file_index);
4566 SIVAL(pdata, 0x48, ea_size);
4567 SIVAL(pdata, 0x4C, access_mask);
4568 SBVAL(pdata, 0x50, pos);
4569 SIVAL(pdata, 0x58, mode); /*TODO: mode != mode fix this!!! */
4570 SIVAL(pdata, 0x5C, 0); /* No alignment needed. */
4572 pdata += 0x60;
4574 len = srvstr_push(dstart, flags2,
4575 pdata+4, dos_fname,
4576 PTR_DIFF(dend, pdata+4),
4577 STR_UNICODE);
4578 SIVAL(pdata,0,len);
4579 pdata += 4 + len;
4580 data_size = PTR_DIFF(pdata,(*ppdata));
4581 break;
4583 case SMB_FILE_INTERNAL_INFORMATION:
4585 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
4586 SBVAL(pdata, 0, file_index);
4587 data_size = 8;
4588 break;
4590 case SMB_FILE_ACCESS_INFORMATION:
4591 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
4592 SIVAL(pdata, 0, access_mask);
4593 data_size = 4;
4594 break;
4596 case SMB_FILE_NAME_INFORMATION:
4597 /* Pathname with leading '\'. */
4599 size_t byte_len;
4600 byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
4601 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
4602 SIVAL(pdata,0,byte_len);
4603 data_size = 4 + byte_len;
4604 break;
4607 case SMB_FILE_DISPOSITION_INFORMATION:
4608 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
4609 data_size = 1;
4610 SCVAL(pdata,0,delete_pending);
4611 break;
4613 case SMB_FILE_POSITION_INFORMATION:
4614 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
4615 data_size = 8;
4616 SOFF_T(pdata,0,pos);
4617 break;
4619 case SMB_FILE_MODE_INFORMATION:
4620 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
4621 SIVAL(pdata,0,mode);
4622 data_size = 4;
4623 break;
4625 case SMB_FILE_ALIGNMENT_INFORMATION:
4626 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
4627 SIVAL(pdata,0,0); /* No alignment needed. */
4628 data_size = 4;
4629 break;
4632 * NT4 server just returns "invalid query" to this - if we try
4633 * to answer it then NTws gets a BSOD! (tridge). W2K seems to
4634 * want this. JRA.
4636 /* The first statement above is false - verified using Thursby
4637 * client against NT4 -- gcolley.
4639 case SMB_QUERY_FILE_STREAM_INFO:
4640 case SMB_FILE_STREAM_INFORMATION: {
4641 unsigned int num_streams;
4642 struct stream_struct *streams;
4644 DEBUG(10,("smbd_do_qfilepathinfo: "
4645 "SMB_FILE_STREAM_INFORMATION\n"));
4647 if (is_ntfs_stream_smb_fname(smb_fname)) {
4648 return NT_STATUS_INVALID_PARAMETER;
4651 status = SMB_VFS_STREAMINFO(
4652 conn, fsp, smb_fname->base_name, talloc_tos(),
4653 &num_streams, &streams);
4655 if (!NT_STATUS_IS_OK(status)) {
4656 DEBUG(10, ("could not get stream info: %s\n",
4657 nt_errstr(status)));
4658 return status;
4661 status = marshall_stream_info(num_streams, streams,
4662 pdata, max_data_bytes,
4663 &data_size);
4665 if (!NT_STATUS_IS_OK(status)) {
4666 DEBUG(10, ("marshall_stream_info failed: %s\n",
4667 nt_errstr(status)));
4668 return status;
4671 TALLOC_FREE(streams);
4673 break;
4675 case SMB_QUERY_COMPRESSION_INFO:
4676 case SMB_FILE_COMPRESSION_INFORMATION:
4677 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
4678 SOFF_T(pdata,0,file_size);
4679 SIVAL(pdata,8,0); /* ??? */
4680 SIVAL(pdata,12,0); /* ??? */
4681 data_size = 16;
4682 break;
4684 case SMB_FILE_NETWORK_OPEN_INFORMATION:
4685 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
4686 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
4687 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
4688 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
4689 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
4690 SOFF_T(pdata,32,allocation_size);
4691 SOFF_T(pdata,40,file_size);
4692 SIVAL(pdata,48,mode);
4693 SIVAL(pdata,52,0); /* ??? */
4694 data_size = 56;
4695 break;
4697 case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
4698 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
4699 SIVAL(pdata,0,mode);
4700 SIVAL(pdata,4,0);
4701 data_size = 8;
4702 break;
4705 * CIFS UNIX Extensions.
4708 case SMB_QUERY_FILE_UNIX_BASIC:
4710 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
4711 data_size = PTR_DIFF(pdata,(*ppdata));
4714 int i;
4715 DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC "));
4717 for (i=0; i<100; i++)
4718 DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
4719 DEBUG(4,("\n"));
4722 break;
4724 case SMB_QUERY_FILE_UNIX_INFO2:
4726 pdata = store_file_unix_basic_info2(conn, pdata, fsp, psbuf);
4727 data_size = PTR_DIFF(pdata,(*ppdata));
4730 int i;
4731 DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));
4733 for (i=0; i<100; i++)
4734 DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
4735 DEBUG(4,("\n"));
4738 break;
4740 case SMB_QUERY_FILE_UNIX_LINK:
4742 int len;
4743 char *buffer = TALLOC_ARRAY(mem_ctx, char, PATH_MAX+1);
4745 if (!buffer) {
4746 return NT_STATUS_NO_MEMORY;
4749 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n"));
4750 #ifdef S_ISLNK
4751 if(!S_ISLNK(psbuf->st_ex_mode)) {
4752 return NT_STATUS_DOS(ERRSRV, ERRbadlink);
4754 #else
4755 return NT_STATUS_DOS(ERRDOS, ERRbadlink);
4756 #endif
4757 len = SMB_VFS_READLINK(conn,
4758 smb_fname->base_name,
4759 buffer, PATH_MAX);
4760 if (len == -1) {
4761 return map_nt_error_from_unix(errno);
4763 buffer[len] = 0;
4764 len = srvstr_push(dstart, flags2,
4765 pdata, buffer,
4766 PTR_DIFF(dend, pdata),
4767 STR_TERMINATE);
4768 pdata += len;
4769 data_size = PTR_DIFF(pdata,(*ppdata));
4771 break;
4774 #if defined(HAVE_POSIX_ACLS)
4775 case SMB_QUERY_POSIX_ACL:
4777 SMB_ACL_T file_acl = NULL;
4778 SMB_ACL_T def_acl = NULL;
4779 uint16 num_file_acls = 0;
4780 uint16 num_def_acls = 0;
4782 if (fsp && !fsp->is_directory && (fsp->fh->fd != -1)) {
4783 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
4784 } else {
4785 file_acl =
4786 SMB_VFS_SYS_ACL_GET_FILE(conn,
4787 smb_fname->base_name,
4788 SMB_ACL_TYPE_ACCESS);
4791 if (file_acl == NULL && no_acl_syscall_error(errno)) {
4792 DEBUG(5,("smbd_do_qfilepathinfo: ACLs "
4793 "not implemented on "
4794 "filesystem containing %s\n",
4795 smb_fname->base_name));
4796 return NT_STATUS_NOT_IMPLEMENTED;
4799 if (S_ISDIR(psbuf->st_ex_mode)) {
4800 if (fsp && fsp->is_directory) {
4801 def_acl =
4802 SMB_VFS_SYS_ACL_GET_FILE(
4803 conn,
4804 fsp->fsp_name->base_name,
4805 SMB_ACL_TYPE_DEFAULT);
4806 } else {
4807 def_acl =
4808 SMB_VFS_SYS_ACL_GET_FILE(
4809 conn,
4810 smb_fname->base_name,
4811 SMB_ACL_TYPE_DEFAULT);
4813 def_acl = free_empty_sys_acl(conn, def_acl);
4816 num_file_acls = count_acl_entries(conn, file_acl);
4817 num_def_acls = count_acl_entries(conn, def_acl);
4819 if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) {
4820 DEBUG(5,("smbd_do_qfilepathinfo: data_size too small (%u) need %u\n",
4821 data_size,
4822 (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
4823 SMB_POSIX_ACL_HEADER_SIZE) ));
4824 if (file_acl) {
4825 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4827 if (def_acl) {
4828 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4830 return NT_STATUS_BUFFER_TOO_SMALL;
4833 SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
4834 SSVAL(pdata,2,num_file_acls);
4835 SSVAL(pdata,4,num_def_acls);
4836 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, psbuf, file_acl)) {
4837 if (file_acl) {
4838 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4840 if (def_acl) {
4841 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4843 return NT_STATUS_INTERNAL_ERROR;
4845 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), psbuf, def_acl)) {
4846 if (file_acl) {
4847 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4849 if (def_acl) {
4850 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4852 return NT_STATUS_INTERNAL_ERROR;
4855 if (file_acl) {
4856 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4858 if (def_acl) {
4859 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4861 data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
4862 break;
4864 #endif
4867 case SMB_QUERY_POSIX_LOCK:
4869 uint64_t count;
4870 uint64_t offset;
4871 uint32 lock_pid;
4872 enum brl_type lock_type;
4874 /* We need an open file with a real fd for this. */
4875 if (!fsp || fsp->is_directory || fsp->fh->fd == -1) {
4876 return NT_STATUS_INVALID_LEVEL;
4879 if (lock_data_count != POSIX_LOCK_DATA_SIZE) {
4880 return NT_STATUS_INVALID_PARAMETER;
4883 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
4884 case POSIX_LOCK_TYPE_READ:
4885 lock_type = READ_LOCK;
4886 break;
4887 case POSIX_LOCK_TYPE_WRITE:
4888 lock_type = WRITE_LOCK;
4889 break;
4890 case POSIX_LOCK_TYPE_UNLOCK:
4891 default:
4892 /* There's no point in asking for an unlock... */
4893 return NT_STATUS_INVALID_PARAMETER;
4896 lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
4897 #if defined(HAVE_LONGLONG)
4898 offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
4899 ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
4900 count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
4901 ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
4902 #else /* HAVE_LONGLONG */
4903 offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET);
4904 count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
4905 #endif /* HAVE_LONGLONG */
4907 status = query_lock(fsp,
4908 &lock_pid,
4909 &count,
4910 &offset,
4911 &lock_type,
4912 POSIX_LOCK);
4914 if (ERROR_WAS_LOCK_DENIED(status)) {
4915 /* Here we need to report who has it locked... */
4916 data_size = POSIX_LOCK_DATA_SIZE;
4918 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
4919 SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
4920 SIVAL(pdata, POSIX_LOCK_PID_OFFSET, lock_pid);
4921 #if defined(HAVE_LONGLONG)
4922 SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF));
4923 SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF));
4924 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF));
4925 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF));
4926 #else /* HAVE_LONGLONG */
4927 SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
4928 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
4929 #endif /* HAVE_LONGLONG */
4931 } else if (NT_STATUS_IS_OK(status)) {
4932 /* For success we just return a copy of what we sent
4933 with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
4934 data_size = POSIX_LOCK_DATA_SIZE;
4935 memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
4936 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
4937 } else {
4938 return status;
4940 break;
4943 default:
4944 return NT_STATUS_INVALID_LEVEL;
4947 *pdata_size = data_size;
4948 return NT_STATUS_OK;
4951 /****************************************************************************
4952 Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
4953 file name or file id).
4954 ****************************************************************************/
4956 static void call_trans2qfilepathinfo(connection_struct *conn,
4957 struct smb_request *req,
4958 unsigned int tran_call,
4959 char **pparams, int total_params,
4960 char **ppdata, int total_data,
4961 unsigned int max_data_bytes)
4963 char *params = *pparams;
4964 char *pdata = *ppdata;
4965 uint16 info_level;
4966 unsigned int data_size = 0;
4967 unsigned int param_size = 2;
4968 struct smb_filename *smb_fname = NULL;
4969 bool delete_pending = False;
4970 struct timespec write_time_ts;
4971 files_struct *fsp = NULL;
4972 struct file_id fileid;
4973 struct ea_list *ea_list = NULL;
4974 int lock_data_count = 0;
4975 char *lock_data = NULL;
4976 bool ms_dfs_link = false;
4977 NTSTATUS status = NT_STATUS_OK;
4979 if (!params) {
4980 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4981 return;
4984 ZERO_STRUCT(write_time_ts);
4986 if (tran_call == TRANSACT2_QFILEINFO) {
4987 if (total_params < 4) {
4988 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4989 return;
4992 if (IS_IPC(conn)) {
4993 call_trans2qpipeinfo(conn, req, tran_call,
4994 pparams, total_params,
4995 ppdata, total_data,
4996 max_data_bytes);
4997 return;
5000 fsp = file_fsp(req, SVAL(params,0));
5001 info_level = SVAL(params,2);
5003 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
5005 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
5006 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5007 return;
5010 /* Initial check for valid fsp ptr. */
5011 if (!check_fsp_open(conn, req, fsp)) {
5012 return;
5015 status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
5016 &smb_fname);
5017 if (!NT_STATUS_IS_OK(status)) {
5018 reply_nterror(req, status);
5019 return;
5022 if(fsp->fake_file_handle) {
5024 * This is actually for the QUOTA_FAKE_FILE --metze
5027 /* We know this name is ok, it's already passed the checks. */
5029 } else if(fsp->is_directory || fsp->fh->fd == -1) {
5031 * This is actually a QFILEINFO on a directory
5032 * handle (returned from an NT SMB). NT5.0 seems
5033 * to do this call. JRA.
5036 if (INFO_LEVEL_IS_UNIX(info_level)) {
5037 /* Always do lstat for UNIX calls. */
5038 if (SMB_VFS_LSTAT(conn, smb_fname)) {
5039 DEBUG(3,("call_trans2qfilepathinfo: "
5040 "SMB_VFS_LSTAT of %s failed "
5041 "(%s)\n",
5042 smb_fname_str_dbg(smb_fname),
5043 strerror(errno)));
5044 reply_nterror(req,
5045 map_nt_error_from_unix(errno));
5046 return;
5048 } else if (SMB_VFS_STAT(conn, smb_fname)) {
5049 DEBUG(3,("call_trans2qfilepathinfo: "
5050 "SMB_VFS_STAT of %s failed (%s)\n",
5051 smb_fname_str_dbg(smb_fname),
5052 strerror(errno)));
5053 reply_nterror(req,
5054 map_nt_error_from_unix(errno));
5055 return;
5058 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5059 get_file_infos(fileid, &delete_pending, &write_time_ts);
5060 } else {
5062 * Original code - this is an open file.
5064 if (!check_fsp(conn, req, fsp)) {
5065 return;
5068 if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
5069 DEBUG(3, ("fstat of fnum %d failed (%s)\n",
5070 fsp->fnum, strerror(errno)));
5071 reply_nterror(req,
5072 map_nt_error_from_unix(errno));
5073 return;
5075 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5076 get_file_infos(fileid, &delete_pending, &write_time_ts);
5079 } else {
5080 char *fname = NULL;
5082 /* qpathinfo */
5083 if (total_params < 7) {
5084 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5085 return;
5088 info_level = SVAL(params,0);
5090 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
5092 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
5093 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5094 return;
5097 srvstr_get_path(req, params, req->flags2, &fname, &params[6],
5098 total_params - 6,
5099 STR_TERMINATE, &status);
5100 if (!NT_STATUS_IS_OK(status)) {
5101 reply_nterror(req, status);
5102 return;
5105 status = filename_convert(req,
5106 conn,
5107 req->flags2 & FLAGS2_DFS_PATHNAMES,
5108 fname,
5110 NULL,
5111 &smb_fname);
5112 if (!NT_STATUS_IS_OK(status)) {
5113 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5114 reply_botherror(req,
5115 NT_STATUS_PATH_NOT_COVERED,
5116 ERRSRV, ERRbadpath);
5117 return;
5119 reply_nterror(req, status);
5120 return;
5123 /* If this is a stream, check if there is a delete_pending. */
5124 if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
5125 && is_ntfs_stream_smb_fname(smb_fname)) {
5126 struct smb_filename *smb_fname_base = NULL;
5128 /* Create an smb_filename with stream_name == NULL. */
5129 status =
5130 create_synthetic_smb_fname(talloc_tos(),
5131 smb_fname->base_name,
5132 NULL, NULL,
5133 &smb_fname_base);
5134 if (!NT_STATUS_IS_OK(status)) {
5135 reply_nterror(req, status);
5136 return;
5139 if (INFO_LEVEL_IS_UNIX(info_level)) {
5140 /* Always do lstat for UNIX calls. */
5141 if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) {
5142 DEBUG(3,("call_trans2qfilepathinfo: "
5143 "SMB_VFS_LSTAT of %s failed "
5144 "(%s)\n",
5145 smb_fname_str_dbg(smb_fname_base),
5146 strerror(errno)));
5147 TALLOC_FREE(smb_fname_base);
5148 reply_nterror(req,
5149 map_nt_error_from_unix(errno));
5150 return;
5152 } else {
5153 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
5154 DEBUG(3,("call_trans2qfilepathinfo: "
5155 "fileinfo of %s failed "
5156 "(%s)\n",
5157 smb_fname_str_dbg(smb_fname_base),
5158 strerror(errno)));
5159 TALLOC_FREE(smb_fname_base);
5160 reply_nterror(req,
5161 map_nt_error_from_unix(errno));
5162 return;
5166 fileid = vfs_file_id_from_sbuf(conn,
5167 &smb_fname_base->st);
5168 TALLOC_FREE(smb_fname_base);
5169 get_file_infos(fileid, &delete_pending, NULL);
5170 if (delete_pending) {
5171 reply_nterror(req, NT_STATUS_DELETE_PENDING);
5172 return;
5176 if (INFO_LEVEL_IS_UNIX(info_level)) {
5177 /* Always do lstat for UNIX calls. */
5178 if (SMB_VFS_LSTAT(conn, smb_fname)) {
5179 DEBUG(3,("call_trans2qfilepathinfo: "
5180 "SMB_VFS_LSTAT of %s failed (%s)\n",
5181 smb_fname_str_dbg(smb_fname),
5182 strerror(errno)));
5183 reply_nterror(req,
5184 map_nt_error_from_unix(errno));
5185 return;
5188 } else if (!VALID_STAT(smb_fname->st) &&
5189 SMB_VFS_STAT(conn, smb_fname) &&
5190 (info_level != SMB_INFO_IS_NAME_VALID)) {
5191 ms_dfs_link = check_msdfs_link(conn,
5192 smb_fname->base_name,
5193 &smb_fname->st);
5195 if (!ms_dfs_link) {
5196 DEBUG(3,("call_trans2qfilepathinfo: "
5197 "SMB_VFS_STAT of %s failed (%s)\n",
5198 smb_fname_str_dbg(smb_fname),
5199 strerror(errno)));
5200 reply_nterror(req,
5201 map_nt_error_from_unix(errno));
5202 return;
5206 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5207 get_file_infos(fileid, &delete_pending, &write_time_ts);
5208 if (delete_pending) {
5209 reply_nterror(req, NT_STATUS_DELETE_PENDING);
5210 return;
5214 DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d "
5215 "total_data=%d\n", smb_fname_str_dbg(smb_fname),
5216 fsp ? fsp->fnum : -1, info_level,tran_call,total_data));
5218 /* Pull out any data sent here before we realloc. */
5219 switch (info_level) {
5220 case SMB_INFO_QUERY_EAS_FROM_LIST:
5222 /* Pull any EA list from the data portion. */
5223 uint32 ea_size;
5225 if (total_data < 4) {
5226 reply_nterror(
5227 req, NT_STATUS_INVALID_PARAMETER);
5228 return;
5230 ea_size = IVAL(pdata,0);
5232 if (total_data > 0 && ea_size != total_data) {
5233 DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
5234 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
5235 reply_nterror(
5236 req, NT_STATUS_INVALID_PARAMETER);
5237 return;
5240 if (!lp_ea_support(SNUM(conn))) {
5241 reply_doserror(req, ERRDOS,
5242 ERReasnotsupported);
5243 return;
5246 /* Pull out the list of names. */
5247 ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4);
5248 if (!ea_list) {
5249 reply_nterror(
5250 req, NT_STATUS_INVALID_PARAMETER);
5251 return;
5253 break;
5256 case SMB_QUERY_POSIX_LOCK:
5258 if (fsp == NULL || fsp->fh->fd == -1) {
5259 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5260 return;
5263 if (total_data != POSIX_LOCK_DATA_SIZE) {
5264 reply_nterror(
5265 req, NT_STATUS_INVALID_PARAMETER);
5266 return;
5269 /* Copy the lock range data. */
5270 lock_data = (char *)TALLOC_MEMDUP(
5271 req, pdata, total_data);
5272 if (!lock_data) {
5273 reply_nterror(req, NT_STATUS_NO_MEMORY);
5274 return;
5276 lock_data_count = total_data;
5278 default:
5279 break;
5282 *pparams = (char *)SMB_REALLOC(*pparams,2);
5283 if (*pparams == NULL) {
5284 reply_nterror(req, NT_STATUS_NO_MEMORY);
5285 return;
5287 params = *pparams;
5288 SSVAL(params,0,0);
5291 * draft-leach-cifs-v1-spec-02.txt
5292 * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path
5293 * says:
5295 * The requested information is placed in the Data portion of the
5296 * transaction response. For the information levels greater than 0x100,
5297 * the transaction response has 1 parameter word which should be
5298 * ignored by the client.
5300 * However Windows only follows this rule for the IS_NAME_VALID call.
5302 switch (info_level) {
5303 case SMB_INFO_IS_NAME_VALID:
5304 param_size = 0;
5305 break;
5308 if ((info_level & 0xFF00) == 0xFF00) {
5310 * We use levels that start with 0xFF00
5311 * internally to represent SMB2 specific levels
5313 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5314 return;
5317 status = smbd_do_qfilepathinfo(conn, req, info_level,
5318 fsp, smb_fname,
5319 delete_pending, write_time_ts,
5320 ms_dfs_link, ea_list,
5321 lock_data_count, lock_data,
5322 req->flags2, max_data_bytes,
5323 ppdata, &data_size);
5324 if (!NT_STATUS_IS_OK(status)) {
5325 reply_nterror(req, status);
5326 return;
5329 send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
5330 max_data_bytes);
5332 return;
5335 /****************************************************************************
5336 Set a hard link (called by UNIX extensions and by NT rename with HARD link
5337 code.
5338 ****************************************************************************/
5340 NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
5341 connection_struct *conn,
5342 const struct smb_filename *smb_fname_old,
5343 const struct smb_filename *smb_fname_new)
5345 NTSTATUS status = NT_STATUS_OK;
5347 /* source must already exist. */
5348 if (!VALID_STAT(smb_fname_old->st)) {
5349 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5352 /* Disallow if newname already exists. */
5353 if (VALID_STAT(smb_fname_new->st)) {
5354 return NT_STATUS_OBJECT_NAME_COLLISION;
5357 /* No links from a directory. */
5358 if (S_ISDIR(smb_fname_old->st.st_ex_mode)) {
5359 return NT_STATUS_FILE_IS_A_DIRECTORY;
5362 /* Setting a hardlink to/from a stream isn't currently supported. */
5363 if (is_ntfs_stream_smb_fname(smb_fname_old) ||
5364 is_ntfs_stream_smb_fname(smb_fname_new)) {
5365 return NT_STATUS_INVALID_PARAMETER;
5368 DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n",
5369 smb_fname_old->base_name, smb_fname_new->base_name));
5371 if (SMB_VFS_LINK(conn, smb_fname_old->base_name,
5372 smb_fname_new->base_name) != 0) {
5373 status = map_nt_error_from_unix(errno);
5374 DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
5375 nt_errstr(status), smb_fname_old->base_name,
5376 smb_fname_new->base_name));
5378 return status;
5381 /****************************************************************************
5382 Deal with setting the time from any of the setfilepathinfo functions.
5383 ****************************************************************************/
5385 NTSTATUS smb_set_file_time(connection_struct *conn,
5386 files_struct *fsp,
5387 const struct smb_filename *smb_fname,
5388 struct smb_file_time *ft,
5389 bool setting_write_time)
5391 struct smb_filename *smb_fname_base = NULL;
5392 uint32 action =
5393 FILE_NOTIFY_CHANGE_LAST_ACCESS
5394 |FILE_NOTIFY_CHANGE_LAST_WRITE
5395 |FILE_NOTIFY_CHANGE_CREATION;
5396 NTSTATUS status;
5398 if (!VALID_STAT(smb_fname->st)) {
5399 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5402 /* get some defaults (no modifications) if any info is zero or -1. */
5403 if (null_timespec(ft->create_time)) {
5404 action &= ~FILE_NOTIFY_CHANGE_CREATION;
5407 if (null_timespec(ft->atime)) {
5408 action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
5411 if (null_timespec(ft->mtime)) {
5412 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
5415 if (!setting_write_time) {
5416 /* ft->mtime comes from change time, not write time. */
5417 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
5420 /* Ensure the resolution is the correct for
5421 * what we can store on this filesystem. */
5423 round_timespec(conn->ts_res, &ft->create_time);
5424 round_timespec(conn->ts_res, &ft->ctime);
5425 round_timespec(conn->ts_res, &ft->atime);
5426 round_timespec(conn->ts_res, &ft->mtime);
5428 DEBUG(5,("smb_set_filetime: actime: %s\n ",
5429 time_to_asc(convert_timespec_to_time_t(ft->atime))));
5430 DEBUG(5,("smb_set_filetime: modtime: %s\n ",
5431 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
5432 DEBUG(5,("smb_set_filetime: ctime: %s\n ",
5433 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
5434 DEBUG(5,("smb_set_file_time: createtime: %s\n ",
5435 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
5437 if (setting_write_time) {
5439 * This was a Windows setfileinfo on an open file.
5440 * NT does this a lot. We also need to
5441 * set the time here, as it can be read by
5442 * FindFirst/FindNext and with the patch for bug #2045
5443 * in smbd/fileio.c it ensures that this timestamp is
5444 * kept sticky even after a write. We save the request
5445 * away and will set it on file close and after a write. JRA.
5448 DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n",
5449 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
5451 if (fsp != NULL) {
5452 if (fsp->base_fsp) {
5453 set_sticky_write_time_fsp(fsp->base_fsp,
5454 ft->mtime);
5455 } else {
5456 set_sticky_write_time_fsp(fsp, ft->mtime);
5458 } else {
5459 set_sticky_write_time_path(
5460 vfs_file_id_from_sbuf(conn, &smb_fname->st),
5461 ft->mtime);
5465 DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
5467 /* Always call ntimes on the base, even if a stream was passed in. */
5468 status = create_synthetic_smb_fname(talloc_tos(), smb_fname->base_name,
5469 NULL, &smb_fname->st,
5470 &smb_fname_base);
5471 if (!NT_STATUS_IS_OK(status)) {
5472 return status;
5475 if(file_ntimes(conn, smb_fname_base, ft)!=0) {
5476 TALLOC_FREE(smb_fname_base);
5477 return map_nt_error_from_unix(errno);
5479 TALLOC_FREE(smb_fname_base);
5481 notify_fname(conn, NOTIFY_ACTION_MODIFIED, action,
5482 smb_fname->base_name);
5483 return NT_STATUS_OK;
5486 /****************************************************************************
5487 Deal with setting the dosmode from any of the setfilepathinfo functions.
5488 ****************************************************************************/
5490 static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
5491 const struct smb_filename *smb_fname,
5492 uint32 dosmode)
5494 struct smb_filename *smb_fname_base = NULL;
5495 NTSTATUS status;
5497 if (!VALID_STAT(smb_fname->st)) {
5498 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5501 /* Always operate on the base_name, even if a stream was passed in. */
5502 status = create_synthetic_smb_fname(talloc_tos(), smb_fname->base_name,
5503 NULL, &smb_fname->st,
5504 &smb_fname_base);
5505 if (!NT_STATUS_IS_OK(status)) {
5506 return status;
5509 if (dosmode) {
5510 if (S_ISDIR(smb_fname_base->st.st_ex_mode)) {
5511 dosmode |= aDIR;
5512 } else {
5513 dosmode &= ~aDIR;
5517 DEBUG(6,("smb_set_file_dosmode: dosmode: 0x%x\n", (unsigned int)dosmode));
5519 /* check the mode isn't different, before changing it */
5520 if ((dosmode != 0) && (dosmode != dos_mode(conn, smb_fname_base))) {
5521 DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode "
5522 "0x%x\n", smb_fname_str_dbg(smb_fname_base),
5523 (unsigned int)dosmode));
5525 if(file_set_dosmode(conn, smb_fname_base, dosmode, NULL,
5526 false)) {
5527 DEBUG(2,("smb_set_file_dosmode: file_set_dosmode of "
5528 "%s failed (%s)\n",
5529 smb_fname_str_dbg(smb_fname_base),
5530 strerror(errno)));
5531 status = map_nt_error_from_unix(errno);
5532 goto out;
5535 status = NT_STATUS_OK;
5536 out:
5537 TALLOC_FREE(smb_fname_base);
5538 return status;
5541 /****************************************************************************
5542 Deal with setting the size from any of the setfilepathinfo functions.
5543 ****************************************************************************/
5545 static NTSTATUS smb_set_file_size(connection_struct *conn,
5546 struct smb_request *req,
5547 files_struct *fsp,
5548 const struct smb_filename *smb_fname,
5549 const SMB_STRUCT_STAT *psbuf,
5550 SMB_OFF_T size)
5552 NTSTATUS status = NT_STATUS_OK;
5553 struct smb_filename *smb_fname_tmp = NULL;
5554 files_struct *new_fsp = NULL;
5556 if (!VALID_STAT(*psbuf)) {
5557 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5560 DEBUG(6,("smb_set_file_size: size: %.0f ", (double)size));
5562 if (size == get_file_size_stat(psbuf)) {
5563 return NT_STATUS_OK;
5566 DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n",
5567 smb_fname_str_dbg(smb_fname), (double)size));
5569 if (fsp && fsp->fh->fd != -1) {
5570 /* Handle based call. */
5571 if (vfs_set_filelen(fsp, size) == -1) {
5572 return map_nt_error_from_unix(errno);
5574 trigger_write_time_update_immediate(fsp);
5575 return NT_STATUS_OK;
5578 status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
5579 if (!NT_STATUS_IS_OK(status)) {
5580 return status;
5583 smb_fname_tmp->st = *psbuf;
5585 status = SMB_VFS_CREATE_FILE(
5586 conn, /* conn */
5587 req, /* req */
5588 0, /* root_dir_fid */
5589 smb_fname_tmp, /* fname */
5590 FILE_WRITE_ATTRIBUTES, /* access_mask */
5591 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5592 FILE_SHARE_DELETE),
5593 FILE_OPEN, /* create_disposition*/
5594 0, /* create_options */
5595 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
5596 FORCE_OPLOCK_BREAK_TO_NONE, /* oplock_request */
5597 0, /* allocation_size */
5598 NULL, /* sd */
5599 NULL, /* ea_list */
5600 &new_fsp, /* result */
5601 NULL); /* pinfo */
5603 TALLOC_FREE(smb_fname_tmp);
5605 if (!NT_STATUS_IS_OK(status)) {
5606 /* NB. We check for open_was_deferred in the caller. */
5607 return status;
5610 if (vfs_set_filelen(new_fsp, size) == -1) {
5611 status = map_nt_error_from_unix(errno);
5612 close_file(req, new_fsp,NORMAL_CLOSE);
5613 return status;
5616 trigger_write_time_update_immediate(new_fsp);
5617 close_file(req, new_fsp,NORMAL_CLOSE);
5618 return NT_STATUS_OK;
5621 /****************************************************************************
5622 Deal with SMB_INFO_SET_EA.
5623 ****************************************************************************/
5625 static NTSTATUS smb_info_set_ea(connection_struct *conn,
5626 const char *pdata,
5627 int total_data,
5628 files_struct *fsp,
5629 const struct smb_filename *smb_fname)
5631 struct ea_list *ea_list = NULL;
5632 TALLOC_CTX *ctx = NULL;
5633 NTSTATUS status = NT_STATUS_OK;
5635 if (total_data < 10) {
5637 /* OS/2 workplace shell seems to send SET_EA requests of "null"
5638 length. They seem to have no effect. Bug #3212. JRA */
5640 if ((total_data == 4) && (IVAL(pdata,0) == 4)) {
5641 /* We're done. We only get EA info in this call. */
5642 return NT_STATUS_OK;
5645 return NT_STATUS_INVALID_PARAMETER;
5648 if (IVAL(pdata,0) > total_data) {
5649 DEBUG(10,("smb_info_set_ea: bad total data size (%u) > %u\n",
5650 IVAL(pdata,0), (unsigned int)total_data));
5651 return NT_STATUS_INVALID_PARAMETER;
5654 ctx = talloc_tos();
5655 ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
5656 if (!ea_list) {
5657 return NT_STATUS_INVALID_PARAMETER;
5659 status = set_ea(conn, fsp, smb_fname, ea_list);
5661 return status;
5664 /****************************************************************************
5665 Deal with SMB_FILE_FULL_EA_INFORMATION set.
5666 ****************************************************************************/
5668 static NTSTATUS smb_set_file_full_ea_info(connection_struct *conn,
5669 const char *pdata,
5670 int total_data,
5671 files_struct *fsp)
5673 struct ea_list *ea_list = NULL;
5674 NTSTATUS status;
5676 if (!fsp) {
5677 return NT_STATUS_INVALID_HANDLE;
5680 if (!lp_ea_support(SNUM(conn))) {
5681 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u but "
5682 "EA's not supported.\n",
5683 (unsigned int)total_data));
5684 return NT_STATUS_EAS_NOT_SUPPORTED;
5687 if (total_data < 10) {
5688 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u "
5689 "too small.\n",
5690 (unsigned int)total_data));
5691 return NT_STATUS_INVALID_PARAMETER;
5694 ea_list = read_nttrans_ea_list(talloc_tos(),
5695 pdata,
5696 total_data);
5698 if (!ea_list) {
5699 return NT_STATUS_INVALID_PARAMETER;
5701 status = set_ea(conn, fsp, fsp->fsp_name, ea_list);
5703 DEBUG(10, ("smb_set_file_full_ea_info on file %s returned %s\n",
5704 smb_fname_str_dbg(fsp->fsp_name),
5705 nt_errstr(status) ));
5707 return status;
5711 /****************************************************************************
5712 Deal with SMB_SET_FILE_DISPOSITION_INFO.
5713 ****************************************************************************/
5715 static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
5716 const char *pdata,
5717 int total_data,
5718 files_struct *fsp,
5719 const struct smb_filename *smb_fname)
5721 NTSTATUS status = NT_STATUS_OK;
5722 bool delete_on_close;
5723 uint32 dosmode = 0;
5725 if (total_data < 1) {
5726 return NT_STATUS_INVALID_PARAMETER;
5729 if (fsp == NULL) {
5730 return NT_STATUS_INVALID_HANDLE;
5733 delete_on_close = (CVAL(pdata,0) ? True : False);
5734 dosmode = dos_mode(conn, smb_fname);
5736 DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
5737 "delete_on_close = %u\n",
5738 smb_fname_str_dbg(smb_fname),
5739 (unsigned int)dosmode,
5740 (unsigned int)delete_on_close ));
5742 status = can_set_delete_on_close(fsp, delete_on_close, dosmode);
5744 if (!NT_STATUS_IS_OK(status)) {
5745 return status;
5748 /* The set is across all open files on this dev/inode pair. */
5749 if (!set_delete_on_close(fsp, delete_on_close,
5750 &conn->server_info->utok)) {
5751 return NT_STATUS_ACCESS_DENIED;
5753 return NT_STATUS_OK;
5756 /****************************************************************************
5757 Deal with SMB_FILE_POSITION_INFORMATION.
5758 ****************************************************************************/
5760 static NTSTATUS smb_file_position_information(connection_struct *conn,
5761 const char *pdata,
5762 int total_data,
5763 files_struct *fsp)
5765 uint64_t position_information;
5767 if (total_data < 8) {
5768 return NT_STATUS_INVALID_PARAMETER;
5771 if (fsp == NULL) {
5772 /* Ignore on pathname based set. */
5773 return NT_STATUS_OK;
5776 position_information = (uint64_t)IVAL(pdata,0);
5777 #ifdef LARGE_SMB_OFF_T
5778 position_information |= (((uint64_t)IVAL(pdata,4)) << 32);
5779 #else /* LARGE_SMB_OFF_T */
5780 if (IVAL(pdata,4) != 0) {
5781 /* more than 32 bits? */
5782 return NT_STATUS_INVALID_PARAMETER;
5784 #endif /* LARGE_SMB_OFF_T */
5786 DEBUG(10,("smb_file_position_information: Set file position "
5787 "information for file %s to %.0f\n", fsp_str_dbg(fsp),
5788 (double)position_information));
5789 fsp->fh->position_information = position_information;
5790 return NT_STATUS_OK;
5793 /****************************************************************************
5794 Deal with SMB_FILE_MODE_INFORMATION.
5795 ****************************************************************************/
5797 static NTSTATUS smb_file_mode_information(connection_struct *conn,
5798 const char *pdata,
5799 int total_data)
5801 uint32 mode;
5803 if (total_data < 4) {
5804 return NT_STATUS_INVALID_PARAMETER;
5806 mode = IVAL(pdata,0);
5807 if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
5808 return NT_STATUS_INVALID_PARAMETER;
5810 return NT_STATUS_OK;
5813 /****************************************************************************
5814 Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
5815 ****************************************************************************/
5817 static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
5818 struct smb_request *req,
5819 const char *pdata,
5820 int total_data,
5821 const struct smb_filename *smb_fname)
5823 char *link_target = NULL;
5824 const char *newname = smb_fname->base_name;
5825 NTSTATUS status = NT_STATUS_OK;
5826 TALLOC_CTX *ctx = talloc_tos();
5828 /* Set a symbolic link. */
5829 /* Don't allow this if follow links is false. */
5831 if (total_data == 0) {
5832 return NT_STATUS_INVALID_PARAMETER;
5835 if (!lp_symlinks(SNUM(conn))) {
5836 return NT_STATUS_ACCESS_DENIED;
5839 srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
5840 total_data, STR_TERMINATE);
5842 if (!link_target) {
5843 return NT_STATUS_INVALID_PARAMETER;
5846 /* !widelinks forces the target path to be within the share. */
5847 /* This means we can interpret the target as a pathname. */
5848 if (!lp_widelinks(SNUM(conn))) {
5849 char *rel_name = NULL;
5850 char *last_dirp = NULL;
5852 if (*link_target == '/') {
5853 /* No absolute paths allowed. */
5854 return NT_STATUS_ACCESS_DENIED;
5856 rel_name = talloc_strdup(ctx,newname);
5857 if (!rel_name) {
5858 return NT_STATUS_NO_MEMORY;
5860 last_dirp = strrchr_m(rel_name, '/');
5861 if (last_dirp) {
5862 last_dirp[1] = '\0';
5863 } else {
5864 rel_name = talloc_strdup(ctx,"./");
5865 if (!rel_name) {
5866 return NT_STATUS_NO_MEMORY;
5869 rel_name = talloc_asprintf_append(rel_name,
5870 "%s",
5871 link_target);
5872 if (!rel_name) {
5873 return NT_STATUS_NO_MEMORY;
5876 status = check_name(conn, rel_name);
5877 if (!NT_STATUS_IS_OK(status)) {
5878 return status;
5882 DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
5883 newname, link_target ));
5885 if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0) {
5886 return map_nt_error_from_unix(errno);
5889 return NT_STATUS_OK;
5892 /****************************************************************************
5893 Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
5894 ****************************************************************************/
5896 static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
5897 struct smb_request *req,
5898 const char *pdata, int total_data,
5899 const struct smb_filename *smb_fname_new)
5901 char *oldname = NULL;
5902 struct smb_filename *smb_fname_old = NULL;
5903 TALLOC_CTX *ctx = talloc_tos();
5904 NTSTATUS status = NT_STATUS_OK;
5906 /* Set a hard link. */
5907 if (total_data == 0) {
5908 return NT_STATUS_INVALID_PARAMETER;
5911 srvstr_get_path(ctx, pdata, req->flags2, &oldname, pdata,
5912 total_data, STR_TERMINATE, &status);
5913 if (!NT_STATUS_IS_OK(status)) {
5914 return status;
5917 DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
5918 smb_fname_str_dbg(smb_fname_new), oldname));
5920 status = filename_convert(ctx,
5921 conn,
5922 req->flags2 & FLAGS2_DFS_PATHNAMES,
5923 oldname,
5925 NULL,
5926 &smb_fname_old);
5927 if (!NT_STATUS_IS_OK(status)) {
5928 return status;
5931 return hardlink_internals(ctx, conn, smb_fname_old, smb_fname_new);
5934 /****************************************************************************
5935 Deal with SMB_FILE_RENAME_INFORMATION.
5936 ****************************************************************************/
5938 static NTSTATUS smb_file_rename_information(connection_struct *conn,
5939 struct smb_request *req,
5940 const char *pdata,
5941 int total_data,
5942 files_struct *fsp,
5943 struct smb_filename *smb_fname_src)
5945 bool overwrite;
5946 uint32 root_fid;
5947 uint32 len;
5948 char *newname = NULL;
5949 struct smb_filename *smb_fname_dst = NULL;
5950 bool dest_has_wcard = False;
5951 NTSTATUS status = NT_STATUS_OK;
5952 char *p;
5953 TALLOC_CTX *ctx = talloc_tos();
5955 if (total_data < 13) {
5956 return NT_STATUS_INVALID_PARAMETER;
5959 overwrite = (CVAL(pdata,0) ? True : False);
5960 root_fid = IVAL(pdata,4);
5961 len = IVAL(pdata,8);
5963 if (len > (total_data - 12) || (len == 0) || (root_fid != 0)) {
5964 return NT_STATUS_INVALID_PARAMETER;
5967 srvstr_get_path_wcard(ctx, pdata, req->flags2, &newname, &pdata[12],
5968 len, 0, &status,
5969 &dest_has_wcard);
5970 if (!NT_STATUS_IS_OK(status)) {
5971 return status;
5974 DEBUG(10,("smb_file_rename_information: got name |%s|\n",
5975 newname));
5977 status = resolve_dfspath_wcard(ctx, conn,
5978 req->flags2 & FLAGS2_DFS_PATHNAMES,
5979 newname,
5980 &newname,
5981 &dest_has_wcard);
5982 if (!NT_STATUS_IS_OK(status)) {
5983 return status;
5986 /* Check the new name has no '/' characters. */
5987 if (strchr_m(newname, '/')) {
5988 return NT_STATUS_NOT_SUPPORTED;
5991 if (fsp && fsp->base_fsp) {
5992 /* newname must be a stream name. */
5993 if (newname[0] != ':') {
5994 return NT_STATUS_NOT_SUPPORTED;
5997 /* Create an smb_fname to call rename_internals_fsp() with. */
5998 status = create_synthetic_smb_fname(talloc_tos(),
5999 fsp->base_fsp->fsp_name->base_name, newname, NULL,
6000 &smb_fname_dst);
6001 if (!NT_STATUS_IS_OK(status)) {
6002 goto out;
6006 * Set the original last component, since
6007 * rename_internals_fsp() requires it.
6009 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6010 newname);
6011 if (smb_fname_dst->original_lcomp == NULL) {
6012 status = NT_STATUS_NO_MEMORY;
6013 goto out;
6016 } else {
6018 * Build up an smb_fname_dst based on the filename passed in.
6019 * We basically just strip off the last component, and put on
6020 * the newname instead.
6022 char *base_name = NULL;
6024 /* newname must *not* be a stream name. */
6025 if (newname[0] == ':') {
6026 return NT_STATUS_NOT_SUPPORTED;
6030 * Strip off the last component (filename) of the path passed
6031 * in.
6033 base_name = talloc_strdup(ctx, smb_fname_src->base_name);
6034 if (!base_name) {
6035 return NT_STATUS_NO_MEMORY;
6037 p = strrchr_m(base_name, '/');
6038 if (p) {
6039 p[1] = '\0';
6040 } else {
6041 base_name = talloc_strdup(ctx, "./");
6042 if (!base_name) {
6043 return NT_STATUS_NO_MEMORY;
6046 /* Append the new name. */
6047 base_name = talloc_asprintf_append(base_name,
6048 "%s",
6049 newname);
6050 if (!base_name) {
6051 return NT_STATUS_NO_MEMORY;
6054 status = unix_convert(ctx, conn, base_name, &smb_fname_dst,
6055 (UCF_SAVE_LCOMP |
6056 (dest_has_wcard ?
6057 UCF_ALWAYS_ALLOW_WCARD_LCOMP :
6058 0)));
6060 /* If an error we expect this to be
6061 * NT_STATUS_OBJECT_PATH_NOT_FOUND */
6063 if (!NT_STATUS_IS_OK(status)) {
6064 if(!NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
6065 status)) {
6066 goto out;
6068 /* Create an smb_fname to call rename_internals_fsp() */
6069 status = create_synthetic_smb_fname(ctx,
6070 base_name, NULL,
6071 NULL,
6072 &smb_fname_dst);
6073 if (!NT_STATUS_IS_OK(status)) {
6074 goto out;
6079 if (fsp) {
6080 DEBUG(10,("smb_file_rename_information: "
6081 "SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
6082 fsp->fnum, fsp_str_dbg(fsp),
6083 smb_fname_str_dbg(smb_fname_dst)));
6084 status = rename_internals_fsp(conn, fsp, smb_fname_dst, 0,
6085 overwrite);
6086 } else {
6087 DEBUG(10,("smb_file_rename_information: "
6088 "SMB_FILE_RENAME_INFORMATION %s -> %s\n",
6089 smb_fname_str_dbg(smb_fname_src),
6090 smb_fname_str_dbg(smb_fname_dst)));
6091 status = rename_internals(ctx, conn, req, smb_fname_src,
6092 smb_fname_dst, 0, overwrite, false,
6093 dest_has_wcard,
6094 FILE_WRITE_ATTRIBUTES);
6096 out:
6097 TALLOC_FREE(smb_fname_dst);
6098 return status;
6101 /****************************************************************************
6102 Deal with SMB_SET_POSIX_ACL.
6103 ****************************************************************************/
6105 #if defined(HAVE_POSIX_ACLS)
6106 static NTSTATUS smb_set_posix_acl(connection_struct *conn,
6107 const char *pdata,
6108 int total_data,
6109 files_struct *fsp,
6110 const struct smb_filename *smb_fname)
6112 uint16 posix_acl_version;
6113 uint16 num_file_acls;
6114 uint16 num_def_acls;
6115 bool valid_file_acls = True;
6116 bool valid_def_acls = True;
6118 if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
6119 return NT_STATUS_INVALID_PARAMETER;
6121 posix_acl_version = SVAL(pdata,0);
6122 num_file_acls = SVAL(pdata,2);
6123 num_def_acls = SVAL(pdata,4);
6125 if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
6126 valid_file_acls = False;
6127 num_file_acls = 0;
6130 if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
6131 valid_def_acls = False;
6132 num_def_acls = 0;
6135 if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
6136 return NT_STATUS_INVALID_PARAMETER;
6139 if (total_data < SMB_POSIX_ACL_HEADER_SIZE +
6140 (num_file_acls+num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE) {
6141 return NT_STATUS_INVALID_PARAMETER;
6144 DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
6145 smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
6146 (unsigned int)num_file_acls,
6147 (unsigned int)num_def_acls));
6149 if (valid_file_acls && !set_unix_posix_acl(conn, fsp,
6150 smb_fname->base_name, num_file_acls,
6151 pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
6152 return map_nt_error_from_unix(errno);
6155 if (valid_def_acls && !set_unix_posix_default_acl(conn,
6156 smb_fname->base_name, &smb_fname->st, num_def_acls,
6157 pdata + SMB_POSIX_ACL_HEADER_SIZE +
6158 (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) {
6159 return map_nt_error_from_unix(errno);
6161 return NT_STATUS_OK;
6163 #endif
6165 /****************************************************************************
6166 Deal with SMB_SET_POSIX_LOCK.
6167 ****************************************************************************/
6169 static NTSTATUS smb_set_posix_lock(connection_struct *conn,
6170 struct smb_request *req,
6171 const char *pdata,
6172 int total_data,
6173 files_struct *fsp)
6175 uint64_t count;
6176 uint64_t offset;
6177 uint32 lock_pid;
6178 bool blocking_lock = False;
6179 enum brl_type lock_type;
6181 NTSTATUS status = NT_STATUS_OK;
6183 if (fsp == NULL || fsp->fh->fd == -1) {
6184 return NT_STATUS_INVALID_HANDLE;
6187 if (total_data != POSIX_LOCK_DATA_SIZE) {
6188 return NT_STATUS_INVALID_PARAMETER;
6191 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
6192 case POSIX_LOCK_TYPE_READ:
6193 lock_type = READ_LOCK;
6194 break;
6195 case POSIX_LOCK_TYPE_WRITE:
6196 /* Return the right POSIX-mappable error code for files opened read-only. */
6197 if (!fsp->can_write) {
6198 return NT_STATUS_INVALID_HANDLE;
6200 lock_type = WRITE_LOCK;
6201 break;
6202 case POSIX_LOCK_TYPE_UNLOCK:
6203 lock_type = UNLOCK_LOCK;
6204 break;
6205 default:
6206 return NT_STATUS_INVALID_PARAMETER;
6209 if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
6210 blocking_lock = False;
6211 } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
6212 blocking_lock = True;
6213 } else {
6214 return NT_STATUS_INVALID_PARAMETER;
6217 if (!lp_blocking_locks(SNUM(conn))) {
6218 blocking_lock = False;
6221 lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
6222 #if defined(HAVE_LONGLONG)
6223 offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
6224 ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
6225 count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
6226 ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
6227 #else /* HAVE_LONGLONG */
6228 offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET);
6229 count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
6230 #endif /* HAVE_LONGLONG */
6232 DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u,"
6233 "lock_pid = %u, count = %.0f, offset = %.0f\n",
6234 fsp_str_dbg(fsp),
6235 (unsigned int)lock_type,
6236 (unsigned int)lock_pid,
6237 (double)count,
6238 (double)offset ));
6240 if (lock_type == UNLOCK_LOCK) {
6241 status = do_unlock(smbd_messaging_context(),
6242 fsp,
6243 lock_pid,
6244 count,
6245 offset,
6246 POSIX_LOCK);
6247 } else {
6248 uint32 block_smbpid;
6250 struct byte_range_lock *br_lck = do_lock(smbd_messaging_context(),
6251 fsp,
6252 lock_pid,
6253 count,
6254 offset,
6255 lock_type,
6256 POSIX_LOCK,
6257 blocking_lock,
6258 &status,
6259 &block_smbpid,
6260 NULL);
6262 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
6264 * A blocking lock was requested. Package up
6265 * this smb into a queued request and push it
6266 * onto the blocking lock queue.
6268 if(push_blocking_lock_request(br_lck,
6269 req,
6270 fsp,
6271 -1, /* infinite timeout. */
6273 lock_pid,
6274 lock_type,
6275 POSIX_LOCK,
6276 offset,
6277 count,
6278 block_smbpid)) {
6279 TALLOC_FREE(br_lck);
6280 return status;
6283 TALLOC_FREE(br_lck);
6286 return status;
6289 /****************************************************************************
6290 Deal with SMB_SET_FILE_BASIC_INFO.
6291 ****************************************************************************/
6293 static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
6294 const char *pdata,
6295 int total_data,
6296 files_struct *fsp,
6297 const struct smb_filename *smb_fname)
6299 /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
6300 struct smb_file_time ft;
6301 uint32 dosmode = 0;
6302 NTSTATUS status = NT_STATUS_OK;
6304 ZERO_STRUCT(ft);
6306 if (total_data < 36) {
6307 return NT_STATUS_INVALID_PARAMETER;
6310 /* Set the attributes */
6311 dosmode = IVAL(pdata,32);
6312 status = smb_set_file_dosmode(conn, smb_fname, dosmode);
6313 if (!NT_STATUS_IS_OK(status)) {
6314 return status;
6317 /* create time */
6318 ft.create_time = interpret_long_date(pdata);
6320 /* access time */
6321 ft.atime = interpret_long_date(pdata+8);
6323 /* write time. */
6324 ft.mtime = interpret_long_date(pdata+16);
6326 /* change time. */
6327 ft.ctime = interpret_long_date(pdata+24);
6329 DEBUG(10, ("smb_set_file_basic_info: file %s\n",
6330 smb_fname_str_dbg(smb_fname)));
6332 return smb_set_file_time(conn, fsp, smb_fname, &ft,
6333 true);
6336 /****************************************************************************
6337 Deal with SMB_INFO_STANDARD.
6338 ****************************************************************************/
6340 static NTSTATUS smb_set_info_standard(connection_struct *conn,
6341 const char *pdata,
6342 int total_data,
6343 files_struct *fsp,
6344 const struct smb_filename *smb_fname)
6346 struct smb_file_time ft;
6348 ZERO_STRUCT(ft);
6350 if (total_data < 12) {
6351 return NT_STATUS_INVALID_PARAMETER;
6354 /* create time */
6355 ft.create_time = convert_time_t_to_timespec(srv_make_unix_date2(pdata));
6356 /* access time */
6357 ft.atime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+4));
6358 /* write time */
6359 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+8));
6361 DEBUG(10,("smb_set_info_standard: file %s\n",
6362 smb_fname_str_dbg(smb_fname)));
6364 return smb_set_file_time(conn,
6365 fsp,
6366 smb_fname,
6367 &ft,
6368 true);
6371 /****************************************************************************
6372 Deal with SMB_SET_FILE_ALLOCATION_INFO.
6373 ****************************************************************************/
6375 static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
6376 struct smb_request *req,
6377 const char *pdata,
6378 int total_data,
6379 files_struct *fsp,
6380 struct smb_filename *smb_fname)
6382 uint64_t allocation_size = 0;
6383 NTSTATUS status = NT_STATUS_OK;
6384 files_struct *new_fsp = NULL;
6386 if (!VALID_STAT(smb_fname->st)) {
6387 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6390 if (total_data < 8) {
6391 return NT_STATUS_INVALID_PARAMETER;
6394 allocation_size = (uint64_t)IVAL(pdata,0);
6395 #ifdef LARGE_SMB_OFF_T
6396 allocation_size |= (((uint64_t)IVAL(pdata,4)) << 32);
6397 #else /* LARGE_SMB_OFF_T */
6398 if (IVAL(pdata,4) != 0) {
6399 /* more than 32 bits? */
6400 return NT_STATUS_INVALID_PARAMETER;
6402 #endif /* LARGE_SMB_OFF_T */
6404 DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for "
6405 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
6406 (double)allocation_size));
6408 if (allocation_size) {
6409 allocation_size = smb_roundup(conn, allocation_size);
6412 DEBUG(10,("smb_set_file_allocation_info: file %s : setting new "
6413 "allocation size to %.0f\n", smb_fname_str_dbg(smb_fname),
6414 (double)allocation_size));
6416 if (fsp && fsp->fh->fd != -1) {
6417 /* Open file handle. */
6418 /* Only change if needed. */
6419 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
6420 if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
6421 return map_nt_error_from_unix(errno);
6424 /* But always update the time. */
6426 * This is equivalent to a write. Ensure it's seen immediately
6427 * if there are no pending writes.
6429 trigger_write_time_update_immediate(fsp);
6430 return NT_STATUS_OK;
6433 /* Pathname or stat or directory file. */
6434 status = SMB_VFS_CREATE_FILE(
6435 conn, /* conn */
6436 req, /* req */
6437 0, /* root_dir_fid */
6438 smb_fname, /* fname */
6439 FILE_WRITE_DATA, /* access_mask */
6440 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6441 FILE_SHARE_DELETE),
6442 FILE_OPEN, /* create_disposition*/
6443 0, /* create_options */
6444 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6445 FORCE_OPLOCK_BREAK_TO_NONE, /* oplock_request */
6446 0, /* allocation_size */
6447 NULL, /* sd */
6448 NULL, /* ea_list */
6449 &new_fsp, /* result */
6450 NULL); /* pinfo */
6452 if (!NT_STATUS_IS_OK(status)) {
6453 /* NB. We check for open_was_deferred in the caller. */
6454 return status;
6457 /* Only change if needed. */
6458 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
6459 if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) {
6460 status = map_nt_error_from_unix(errno);
6461 close_file(req, new_fsp, NORMAL_CLOSE);
6462 return status;
6466 /* Changing the allocation size should set the last mod time. */
6468 * This is equivalent to a write. Ensure it's seen immediately
6469 * if there are no pending writes.
6471 trigger_write_time_update_immediate(new_fsp);
6473 close_file(req, new_fsp, NORMAL_CLOSE);
6474 return NT_STATUS_OK;
6477 /****************************************************************************
6478 Deal with SMB_SET_FILE_END_OF_FILE_INFO.
6479 ****************************************************************************/
6481 static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
6482 struct smb_request *req,
6483 const char *pdata,
6484 int total_data,
6485 files_struct *fsp,
6486 const struct smb_filename *smb_fname)
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);
6514 /****************************************************************************
6515 Allow a UNIX info mknod.
6516 ****************************************************************************/
6518 static NTSTATUS smb_unix_mknod(connection_struct *conn,
6519 const char *pdata,
6520 int total_data,
6521 const struct smb_filename *smb_fname)
6523 uint32 file_type = IVAL(pdata,56);
6524 #if defined(HAVE_MAKEDEV)
6525 uint32 dev_major = IVAL(pdata,60);
6526 uint32 dev_minor = IVAL(pdata,68);
6527 #endif
6528 SMB_DEV_T dev = (SMB_DEV_T)0;
6529 uint32 raw_unixmode = IVAL(pdata,84);
6530 NTSTATUS status;
6531 mode_t unixmode;
6533 if (total_data < 100) {
6534 return NT_STATUS_INVALID_PARAMETER;
6537 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6538 PERM_NEW_FILE, &unixmode);
6539 if (!NT_STATUS_IS_OK(status)) {
6540 return status;
6543 #if defined(HAVE_MAKEDEV)
6544 dev = makedev(dev_major, dev_minor);
6545 #endif
6547 switch (file_type) {
6548 #if defined(S_IFIFO)
6549 case UNIX_TYPE_FIFO:
6550 unixmode |= S_IFIFO;
6551 break;
6552 #endif
6553 #if defined(S_IFSOCK)
6554 case UNIX_TYPE_SOCKET:
6555 unixmode |= S_IFSOCK;
6556 break;
6557 #endif
6558 #if defined(S_IFCHR)
6559 case UNIX_TYPE_CHARDEV:
6560 unixmode |= S_IFCHR;
6561 break;
6562 #endif
6563 #if defined(S_IFBLK)
6564 case UNIX_TYPE_BLKDEV:
6565 unixmode |= S_IFBLK;
6566 break;
6567 #endif
6568 default:
6569 return NT_STATUS_INVALID_PARAMETER;
6572 DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
6573 "%.0f mode 0%o for file %s\n", (double)dev,
6574 (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
6576 /* Ok - do the mknod. */
6577 if (SMB_VFS_MKNOD(conn, smb_fname->base_name, unixmode, dev) != 0) {
6578 return map_nt_error_from_unix(errno);
6581 /* If any of the other "set" calls fail we
6582 * don't want to end up with a half-constructed mknod.
6585 if (lp_inherit_perms(SNUM(conn))) {
6586 char *parent;
6587 if (!parent_dirname(talloc_tos(), smb_fname->base_name,
6588 &parent, NULL)) {
6589 return NT_STATUS_NO_MEMORY;
6591 inherit_access_posix_acl(conn, parent, smb_fname->base_name,
6592 unixmode);
6593 TALLOC_FREE(parent);
6596 return NT_STATUS_OK;
6599 /****************************************************************************
6600 Deal with SMB_SET_FILE_UNIX_BASIC.
6601 ****************************************************************************/
6603 static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
6604 struct smb_request *req,
6605 const char *pdata,
6606 int total_data,
6607 files_struct *fsp,
6608 const struct smb_filename *smb_fname)
6610 struct smb_file_time ft;
6611 uint32 raw_unixmode;
6612 mode_t unixmode;
6613 SMB_OFF_T size = 0;
6614 uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
6615 gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
6616 NTSTATUS status = NT_STATUS_OK;
6617 bool delete_on_fail = False;
6618 enum perm_type ptype;
6619 files_struct *all_fsps = NULL;
6620 bool modify_mtime = true;
6621 struct file_id id;
6622 SMB_STRUCT_STAT sbuf;
6624 ZERO_STRUCT(ft);
6626 if (total_data < 100) {
6627 return NT_STATUS_INVALID_PARAMETER;
6630 if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
6631 IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
6632 size=IVAL(pdata,0); /* first 8 Bytes are size */
6633 #ifdef LARGE_SMB_OFF_T
6634 size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
6635 #else /* LARGE_SMB_OFF_T */
6636 if (IVAL(pdata,4) != 0) {
6637 /* more than 32 bits? */
6638 return NT_STATUS_INVALID_PARAMETER;
6640 #endif /* LARGE_SMB_OFF_T */
6643 ft.atime = interpret_long_date(pdata+24); /* access_time */
6644 ft.mtime = interpret_long_date(pdata+32); /* modification_time */
6645 set_owner = (uid_t)IVAL(pdata,40);
6646 set_grp = (gid_t)IVAL(pdata,48);
6647 raw_unixmode = IVAL(pdata,84);
6649 if (VALID_STAT(smb_fname->st)) {
6650 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
6651 ptype = PERM_EXISTING_DIR;
6652 } else {
6653 ptype = PERM_EXISTING_FILE;
6655 } else {
6656 ptype = PERM_NEW_FILE;
6659 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6660 ptype, &unixmode);
6661 if (!NT_STATUS_IS_OK(status)) {
6662 return status;
6665 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
6666 "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
6667 smb_fname_str_dbg(smb_fname), (double)size,
6668 (unsigned int)set_owner, (unsigned int)set_grp,
6669 (int)raw_unixmode));
6671 sbuf = smb_fname->st;
6673 if (!VALID_STAT(sbuf)) {
6674 struct smb_filename *smb_fname_tmp = NULL;
6676 * The only valid use of this is to create character and block
6677 * devices, and named pipes. This is deprecated (IMHO) and
6678 * a new info level should be used for mknod. JRA.
6681 status = smb_unix_mknod(conn,
6682 pdata,
6683 total_data,
6684 smb_fname);
6685 if (!NT_STATUS_IS_OK(status)) {
6686 return status;
6689 status = copy_smb_filename(talloc_tos(), smb_fname,
6690 &smb_fname_tmp);
6691 if (!NT_STATUS_IS_OK(status)) {
6692 return status;
6695 if (SMB_VFS_STAT(conn, smb_fname_tmp) != 0) {
6696 status = map_nt_error_from_unix(errno);
6697 TALLOC_FREE(smb_fname_tmp);
6698 SMB_VFS_UNLINK(conn, smb_fname);
6699 return status;
6702 sbuf = smb_fname_tmp->st;
6703 TALLOC_FREE(smb_fname_tmp);
6705 /* Ensure we don't try and change anything else. */
6706 raw_unixmode = SMB_MODE_NO_CHANGE;
6707 size = get_file_size_stat(&sbuf);
6708 ft.atime = sbuf.st_ex_atime;
6709 ft.mtime = sbuf.st_ex_mtime;
6711 * We continue here as we might want to change the
6712 * owner uid/gid.
6714 delete_on_fail = True;
6717 #if 1
6718 /* Horrible backwards compatibility hack as an old server bug
6719 * allowed a CIFS client bug to remain unnoticed :-(. JRA.
6720 * */
6722 if (!size) {
6723 size = get_file_size_stat(&sbuf);
6725 #endif
6728 * Deal with the UNIX specific mode set.
6731 if (raw_unixmode != SMB_MODE_NO_CHANGE) {
6732 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6733 "setting mode 0%o for file %s\n",
6734 (unsigned int)unixmode,
6735 smb_fname_str_dbg(smb_fname)));
6736 if (SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode) != 0) {
6737 return map_nt_error_from_unix(errno);
6742 * Deal with the UNIX specific uid set.
6745 if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
6746 (sbuf.st_ex_uid != set_owner)) {
6747 int ret;
6749 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6750 "changing owner %u for path %s\n",
6751 (unsigned int)set_owner,
6752 smb_fname_str_dbg(smb_fname)));
6754 if (S_ISLNK(sbuf.st_ex_mode)) {
6755 ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name,
6756 set_owner, (gid_t)-1);
6757 } else {
6758 ret = SMB_VFS_CHOWN(conn, smb_fname->base_name,
6759 set_owner, (gid_t)-1);
6762 if (ret != 0) {
6763 status = map_nt_error_from_unix(errno);
6764 if (delete_on_fail) {
6765 SMB_VFS_UNLINK(conn, smb_fname);
6767 return status;
6772 * Deal with the UNIX specific gid set.
6775 if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
6776 (sbuf.st_ex_gid != set_grp)) {
6777 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6778 "changing group %u for file %s\n",
6779 (unsigned int)set_owner,
6780 smb_fname_str_dbg(smb_fname)));
6781 if (SMB_VFS_CHOWN(conn, smb_fname->base_name, (uid_t)-1,
6782 set_grp) != 0) {
6783 status = map_nt_error_from_unix(errno);
6784 if (delete_on_fail) {
6785 SMB_VFS_UNLINK(conn, smb_fname);
6787 return status;
6791 /* Deal with any size changes. */
6793 status = smb_set_file_size(conn, req,
6794 fsp,
6795 smb_fname,
6796 &sbuf,
6797 size);
6798 if (!NT_STATUS_IS_OK(status)) {
6799 return status;
6802 /* Deal with any time changes. */
6803 if (null_timespec(ft.mtime) && null_timespec(ft.atime)) {
6804 /* No change, don't cancel anything. */
6805 return status;
6808 id = vfs_file_id_from_sbuf(conn, &sbuf);
6809 for(all_fsps = file_find_di_first(id); all_fsps;
6810 all_fsps = file_find_di_next(all_fsps)) {
6812 * We're setting the time explicitly for UNIX.
6813 * Cancel any pending changes over all handles.
6815 all_fsps->update_write_time_on_close = false;
6816 TALLOC_FREE(all_fsps->update_write_time_event);
6820 * Override the "setting_write_time"
6821 * parameter here as it almost does what
6822 * we need. Just remember if we modified
6823 * mtime and send the notify ourselves.
6825 if (null_timespec(ft.mtime)) {
6826 modify_mtime = false;
6829 status = smb_set_file_time(conn,
6830 fsp,
6831 smb_fname,
6832 &ft,
6833 false);
6834 if (modify_mtime) {
6835 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6836 FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
6838 return status;
6841 /****************************************************************************
6842 Deal with SMB_SET_FILE_UNIX_INFO2.
6843 ****************************************************************************/
6845 static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
6846 struct smb_request *req,
6847 const char *pdata,
6848 int total_data,
6849 files_struct *fsp,
6850 const struct smb_filename *smb_fname)
6852 NTSTATUS status;
6853 uint32 smb_fflags;
6854 uint32 smb_fmask;
6856 if (total_data < 116) {
6857 return NT_STATUS_INVALID_PARAMETER;
6860 /* Start by setting all the fields that are common between UNIX_BASIC
6861 * and UNIX_INFO2.
6863 status = smb_set_file_unix_basic(conn, req, pdata, total_data,
6864 fsp, smb_fname);
6865 if (!NT_STATUS_IS_OK(status)) {
6866 return status;
6869 smb_fflags = IVAL(pdata, 108);
6870 smb_fmask = IVAL(pdata, 112);
6872 /* NB: We should only attempt to alter the file flags if the client
6873 * sends a non-zero mask.
6875 if (smb_fmask != 0) {
6876 int stat_fflags = 0;
6878 if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
6879 smb_fmask, &stat_fflags)) {
6880 /* Client asked to alter a flag we don't understand. */
6881 return NT_STATUS_INVALID_PARAMETER;
6884 if (fsp && fsp->fh->fd != -1) {
6885 /* XXX: we should be using SMB_VFS_FCHFLAGS here. */
6886 return NT_STATUS_NOT_SUPPORTED;
6887 } else {
6888 if (SMB_VFS_CHFLAGS(conn, smb_fname->base_name,
6889 stat_fflags) != 0) {
6890 return map_nt_error_from_unix(errno);
6895 /* XXX: need to add support for changing the create_time here. You
6896 * can do this for paths on Darwin with setattrlist(2). The right way
6897 * to hook this up is probably by extending the VFS utimes interface.
6900 return NT_STATUS_OK;
6903 /****************************************************************************
6904 Create a directory with POSIX semantics.
6905 ****************************************************************************/
6907 static NTSTATUS smb_posix_mkdir(connection_struct *conn,
6908 struct smb_request *req,
6909 char **ppdata,
6910 int total_data,
6911 struct smb_filename *smb_fname,
6912 int *pdata_return_size)
6914 NTSTATUS status = NT_STATUS_OK;
6915 uint32 raw_unixmode = 0;
6916 uint32 mod_unixmode = 0;
6917 mode_t unixmode = (mode_t)0;
6918 files_struct *fsp = NULL;
6919 uint16 info_level_return = 0;
6920 int info;
6921 char *pdata = *ppdata;
6923 if (total_data < 18) {
6924 return NT_STATUS_INVALID_PARAMETER;
6927 raw_unixmode = IVAL(pdata,8);
6928 /* Next 4 bytes are not yet defined. */
6930 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6931 PERM_NEW_DIR, &unixmode);
6932 if (!NT_STATUS_IS_OK(status)) {
6933 return status;
6936 mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
6938 DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
6939 smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
6941 status = SMB_VFS_CREATE_FILE(
6942 conn, /* conn */
6943 req, /* req */
6944 0, /* root_dir_fid */
6945 smb_fname, /* fname */
6946 FILE_READ_ATTRIBUTES, /* access_mask */
6947 FILE_SHARE_NONE, /* share_access */
6948 FILE_CREATE, /* create_disposition*/
6949 FILE_DIRECTORY_FILE, /* create_options */
6950 mod_unixmode, /* file_attributes */
6951 0, /* oplock_request */
6952 0, /* allocation_size */
6953 NULL, /* sd */
6954 NULL, /* ea_list */
6955 &fsp, /* result */
6956 &info); /* pinfo */
6958 if (NT_STATUS_IS_OK(status)) {
6959 close_file(req, fsp, NORMAL_CLOSE);
6962 info_level_return = SVAL(pdata,16);
6964 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
6965 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
6966 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
6967 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
6968 } else {
6969 *pdata_return_size = 12;
6972 /* Realloc the data size */
6973 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
6974 if (*ppdata == NULL) {
6975 *pdata_return_size = 0;
6976 return NT_STATUS_NO_MEMORY;
6978 pdata = *ppdata;
6980 SSVAL(pdata,0,NO_OPLOCK_RETURN);
6981 SSVAL(pdata,2,0); /* No fnum. */
6982 SIVAL(pdata,4,info); /* Was directory created. */
6984 switch (info_level_return) {
6985 case SMB_QUERY_FILE_UNIX_BASIC:
6986 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
6987 SSVAL(pdata,10,0); /* Padding. */
6988 store_file_unix_basic(conn, pdata + 12, fsp,
6989 &smb_fname->st);
6990 break;
6991 case SMB_QUERY_FILE_UNIX_INFO2:
6992 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
6993 SSVAL(pdata,10,0); /* Padding. */
6994 store_file_unix_basic_info2(conn, pdata + 12, fsp,
6995 &smb_fname->st);
6996 break;
6997 default:
6998 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
6999 SSVAL(pdata,10,0); /* Padding. */
7000 break;
7003 return status;
7006 /****************************************************************************
7007 Open/Create a file with POSIX semantics.
7008 ****************************************************************************/
7010 static NTSTATUS smb_posix_open(connection_struct *conn,
7011 struct smb_request *req,
7012 char **ppdata,
7013 int total_data,
7014 struct smb_filename *smb_fname,
7015 int *pdata_return_size)
7017 bool extended_oplock_granted = False;
7018 char *pdata = *ppdata;
7019 uint32 flags = 0;
7020 uint32 wire_open_mode = 0;
7021 uint32 raw_unixmode = 0;
7022 uint32 mod_unixmode = 0;
7023 uint32 create_disp = 0;
7024 uint32 access_mask = 0;
7025 uint32 create_options = 0;
7026 NTSTATUS status = NT_STATUS_OK;
7027 mode_t unixmode = (mode_t)0;
7028 files_struct *fsp = NULL;
7029 int oplock_request = 0;
7030 int info = 0;
7031 uint16 info_level_return = 0;
7033 if (total_data < 18) {
7034 return NT_STATUS_INVALID_PARAMETER;
7037 flags = IVAL(pdata,0);
7038 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
7039 if (oplock_request) {
7040 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
7043 wire_open_mode = IVAL(pdata,4);
7045 if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
7046 return smb_posix_mkdir(conn, req,
7047 ppdata,
7048 total_data,
7049 smb_fname,
7050 pdata_return_size);
7053 switch (wire_open_mode & SMB_ACCMODE) {
7054 case SMB_O_RDONLY:
7055 access_mask = FILE_READ_DATA;
7056 break;
7057 case SMB_O_WRONLY:
7058 access_mask = FILE_WRITE_DATA;
7059 break;
7060 case SMB_O_RDWR:
7061 access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
7062 break;
7063 default:
7064 DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
7065 (unsigned int)wire_open_mode ));
7066 return NT_STATUS_INVALID_PARAMETER;
7069 wire_open_mode &= ~SMB_ACCMODE;
7071 if((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) == (SMB_O_CREAT | SMB_O_EXCL)) {
7072 create_disp = FILE_CREATE;
7073 } else if((wire_open_mode & (SMB_O_CREAT | SMB_O_TRUNC)) == (SMB_O_CREAT | SMB_O_TRUNC)) {
7074 create_disp = FILE_OVERWRITE_IF;
7075 } else if((wire_open_mode & SMB_O_CREAT) == SMB_O_CREAT) {
7076 create_disp = FILE_OPEN_IF;
7077 } else if ((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL | SMB_O_TRUNC)) == 0) {
7078 create_disp = FILE_OPEN;
7079 } else {
7080 DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
7081 (unsigned int)wire_open_mode ));
7082 return NT_STATUS_INVALID_PARAMETER;
7085 raw_unixmode = IVAL(pdata,8);
7086 /* Next 4 bytes are not yet defined. */
7088 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
7089 (VALID_STAT(smb_fname->st) ?
7090 PERM_EXISTING_FILE : PERM_NEW_FILE),
7091 &unixmode);
7093 if (!NT_STATUS_IS_OK(status)) {
7094 return status;
7097 mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
7099 if (wire_open_mode & SMB_O_SYNC) {
7100 create_options |= FILE_WRITE_THROUGH;
7102 if (wire_open_mode & SMB_O_APPEND) {
7103 access_mask |= FILE_APPEND_DATA;
7105 if (wire_open_mode & SMB_O_DIRECT) {
7106 mod_unixmode |= FILE_FLAG_NO_BUFFERING;
7109 DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
7110 smb_fname_str_dbg(smb_fname),
7111 (unsigned int)wire_open_mode,
7112 (unsigned int)unixmode ));
7114 status = SMB_VFS_CREATE_FILE(
7115 conn, /* conn */
7116 req, /* req */
7117 0, /* root_dir_fid */
7118 smb_fname, /* fname */
7119 access_mask, /* access_mask */
7120 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7121 FILE_SHARE_DELETE),
7122 create_disp, /* create_disposition*/
7123 FILE_NON_DIRECTORY_FILE, /* create_options */
7124 mod_unixmode, /* file_attributes */
7125 oplock_request, /* oplock_request */
7126 0, /* allocation_size */
7127 NULL, /* sd */
7128 NULL, /* ea_list */
7129 &fsp, /* result */
7130 &info); /* pinfo */
7132 if (!NT_STATUS_IS_OK(status)) {
7133 return status;
7136 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
7137 extended_oplock_granted = True;
7140 if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
7141 extended_oplock_granted = True;
7144 info_level_return = SVAL(pdata,16);
7146 /* Allocate the correct return size. */
7148 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
7149 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
7150 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
7151 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
7152 } else {
7153 *pdata_return_size = 12;
7156 /* Realloc the data size */
7157 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
7158 if (*ppdata == NULL) {
7159 close_file(req, fsp, ERROR_CLOSE);
7160 *pdata_return_size = 0;
7161 return NT_STATUS_NO_MEMORY;
7163 pdata = *ppdata;
7165 if (extended_oplock_granted) {
7166 if (flags & REQUEST_BATCH_OPLOCK) {
7167 SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
7168 } else {
7169 SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
7171 } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
7172 SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
7173 } else {
7174 SSVAL(pdata,0,NO_OPLOCK_RETURN);
7177 SSVAL(pdata,2,fsp->fnum);
7178 SIVAL(pdata,4,info); /* Was file created etc. */
7180 switch (info_level_return) {
7181 case SMB_QUERY_FILE_UNIX_BASIC:
7182 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
7183 SSVAL(pdata,10,0); /* padding. */
7184 store_file_unix_basic(conn, pdata + 12, fsp,
7185 &smb_fname->st);
7186 break;
7187 case SMB_QUERY_FILE_UNIX_INFO2:
7188 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
7189 SSVAL(pdata,10,0); /* padding. */
7190 store_file_unix_basic_info2(conn, pdata + 12, fsp,
7191 &smb_fname->st);
7192 break;
7193 default:
7194 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
7195 SSVAL(pdata,10,0); /* padding. */
7196 break;
7198 return NT_STATUS_OK;
7201 /****************************************************************************
7202 Delete a file with POSIX semantics.
7203 ****************************************************************************/
7205 static NTSTATUS smb_posix_unlink(connection_struct *conn,
7206 struct smb_request *req,
7207 const char *pdata,
7208 int total_data,
7209 struct smb_filename *smb_fname)
7211 NTSTATUS status = NT_STATUS_OK;
7212 files_struct *fsp = NULL;
7213 uint16 flags = 0;
7214 char del = 1;
7215 int info = 0;
7216 int create_options = 0;
7217 int i;
7218 struct share_mode_lock *lck = NULL;
7220 if (total_data < 2) {
7221 return NT_STATUS_INVALID_PARAMETER;
7224 flags = SVAL(pdata,0);
7226 if (!VALID_STAT(smb_fname->st)) {
7227 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
7230 if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
7231 !VALID_STAT_OF_DIR(smb_fname->st)) {
7232 return NT_STATUS_NOT_A_DIRECTORY;
7235 DEBUG(10,("smb_posix_unlink: %s %s\n",
7236 (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
7237 smb_fname_str_dbg(smb_fname)));
7239 if (VALID_STAT_OF_DIR(smb_fname->st)) {
7240 create_options |= FILE_DIRECTORY_FILE;
7243 status = SMB_VFS_CREATE_FILE(
7244 conn, /* conn */
7245 req, /* req */
7246 0, /* root_dir_fid */
7247 smb_fname, /* fname */
7248 DELETE_ACCESS, /* access_mask */
7249 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7250 FILE_SHARE_DELETE),
7251 FILE_OPEN, /* create_disposition*/
7252 create_options, /* create_options */
7253 FILE_FLAG_POSIX_SEMANTICS|0777, /* file_attributes */
7254 0, /* oplock_request */
7255 0, /* allocation_size */
7256 NULL, /* sd */
7257 NULL, /* ea_list */
7258 &fsp, /* result */
7259 &info); /* pinfo */
7261 if (!NT_STATUS_IS_OK(status)) {
7262 return status;
7266 * Don't lie to client. If we can't really delete due to
7267 * non-POSIX opens return SHARING_VIOLATION.
7270 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
7271 NULL);
7272 if (lck == NULL) {
7273 DEBUG(0, ("smb_posix_unlink: Could not get share mode "
7274 "lock for file %s\n", fsp_str_dbg(fsp)));
7275 close_file(req, fsp, NORMAL_CLOSE);
7276 return NT_STATUS_INVALID_PARAMETER;
7280 * See if others still have the file open. If this is the case, then
7281 * don't delete. If all opens are POSIX delete we can set the delete
7282 * on close disposition.
7284 for (i=0; i<lck->num_share_modes; i++) {
7285 struct share_mode_entry *e = &lck->share_modes[i];
7286 if (is_valid_share_mode_entry(e)) {
7287 if (e->flags & SHARE_MODE_FLAG_POSIX_OPEN) {
7288 continue;
7290 /* Fail with sharing violation. */
7291 close_file(req, fsp, NORMAL_CLOSE);
7292 TALLOC_FREE(lck);
7293 return NT_STATUS_SHARING_VIOLATION;
7298 * Set the delete on close.
7300 status = smb_set_file_disposition_info(conn,
7301 &del,
7303 fsp,
7304 smb_fname);
7306 if (!NT_STATUS_IS_OK(status)) {
7307 close_file(req, fsp, NORMAL_CLOSE);
7308 TALLOC_FREE(lck);
7309 return status;
7311 TALLOC_FREE(lck);
7312 return close_file(req, fsp, NORMAL_CLOSE);
7315 NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
7316 struct smb_request *req,
7317 TALLOC_CTX *mem_ctx,
7318 uint16_t info_level,
7319 files_struct *fsp,
7320 struct smb_filename *smb_fname,
7321 char **ppdata, int total_data,
7322 int *ret_data_size)
7324 char *pdata = *ppdata;
7325 NTSTATUS status = NT_STATUS_OK;
7326 int data_return_size = 0;
7328 *ret_data_size = 0;
7330 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
7331 return NT_STATUS_INVALID_LEVEL;
7334 if (!CAN_WRITE(conn)) {
7335 /* Allow POSIX opens. The open path will deny
7336 * any non-readonly opens. */
7337 if (info_level != SMB_POSIX_PATH_OPEN) {
7338 return NT_STATUS_DOS(ERRSRV, ERRaccess);
7342 DEBUG(3,("smbd_do_setfilepathinfo: %s (fnum %d) info_level=%d "
7343 "totdata=%d\n", smb_fname_str_dbg(smb_fname),
7344 fsp ? fsp->fnum : -1, info_level, total_data));
7346 switch (info_level) {
7348 case SMB_INFO_STANDARD:
7350 status = smb_set_info_standard(conn,
7351 pdata,
7352 total_data,
7353 fsp,
7354 smb_fname);
7355 break;
7358 case SMB_INFO_SET_EA:
7360 status = smb_info_set_ea(conn,
7361 pdata,
7362 total_data,
7363 fsp,
7364 smb_fname);
7365 break;
7368 case SMB_SET_FILE_BASIC_INFO:
7369 case SMB_FILE_BASIC_INFORMATION:
7371 status = smb_set_file_basic_info(conn,
7372 pdata,
7373 total_data,
7374 fsp,
7375 smb_fname);
7376 break;
7379 case SMB_FILE_ALLOCATION_INFORMATION:
7380 case SMB_SET_FILE_ALLOCATION_INFO:
7382 status = smb_set_file_allocation_info(conn, req,
7383 pdata,
7384 total_data,
7385 fsp,
7386 smb_fname);
7387 break;
7390 case SMB_FILE_END_OF_FILE_INFORMATION:
7391 case SMB_SET_FILE_END_OF_FILE_INFO:
7393 status = smb_set_file_end_of_file_info(conn, req,
7394 pdata,
7395 total_data,
7396 fsp,
7397 smb_fname);
7398 break;
7401 case SMB_FILE_DISPOSITION_INFORMATION:
7402 case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
7404 #if 0
7405 /* JRA - We used to just ignore this on a path ?
7406 * Shouldn't this be invalid level on a pathname
7407 * based call ?
7409 if (tran_call != TRANSACT2_SETFILEINFO) {
7410 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
7412 #endif
7413 status = smb_set_file_disposition_info(conn,
7414 pdata,
7415 total_data,
7416 fsp,
7417 smb_fname);
7418 break;
7421 case SMB_FILE_POSITION_INFORMATION:
7423 status = smb_file_position_information(conn,
7424 pdata,
7425 total_data,
7426 fsp);
7427 break;
7430 case SMB_FILE_FULL_EA_INFORMATION:
7432 status = smb_set_file_full_ea_info(conn,
7433 pdata,
7434 total_data,
7435 fsp);
7436 break;
7439 /* From tridge Samba4 :
7440 * MODE_INFORMATION in setfileinfo (I have no
7441 * idea what "mode information" on a file is - it takes a value of 0,
7442 * 2, 4 or 6. What could it be?).
7445 case SMB_FILE_MODE_INFORMATION:
7447 status = smb_file_mode_information(conn,
7448 pdata,
7449 total_data);
7450 break;
7454 * CIFS UNIX extensions.
7457 case SMB_SET_FILE_UNIX_BASIC:
7459 status = smb_set_file_unix_basic(conn, req,
7460 pdata,
7461 total_data,
7462 fsp,
7463 smb_fname);
7464 break;
7467 case SMB_SET_FILE_UNIX_INFO2:
7469 status = smb_set_file_unix_info2(conn, req,
7470 pdata,
7471 total_data,
7472 fsp,
7473 smb_fname);
7474 break;
7477 case SMB_SET_FILE_UNIX_LINK:
7479 if (fsp) {
7480 /* We must have a pathname for this. */
7481 return NT_STATUS_INVALID_LEVEL;
7483 status = smb_set_file_unix_link(conn, req, pdata,
7484 total_data, smb_fname);
7485 break;
7488 case SMB_SET_FILE_UNIX_HLINK:
7490 if (fsp) {
7491 /* We must have a pathname for this. */
7492 return NT_STATUS_INVALID_LEVEL;
7494 status = smb_set_file_unix_hlink(conn, req,
7495 pdata, total_data,
7496 smb_fname);
7497 break;
7500 case SMB_FILE_RENAME_INFORMATION:
7502 status = smb_file_rename_information(conn, req,
7503 pdata, total_data,
7504 fsp, smb_fname);
7505 break;
7508 #if defined(HAVE_POSIX_ACLS)
7509 case SMB_SET_POSIX_ACL:
7511 status = smb_set_posix_acl(conn,
7512 pdata,
7513 total_data,
7514 fsp,
7515 smb_fname);
7516 break;
7518 #endif
7520 case SMB_SET_POSIX_LOCK:
7522 if (!fsp) {
7523 return NT_STATUS_INVALID_LEVEL;
7525 status = smb_set_posix_lock(conn, req,
7526 pdata, total_data, fsp);
7527 break;
7530 case SMB_POSIX_PATH_OPEN:
7532 if (fsp) {
7533 /* We must have a pathname for this. */
7534 return NT_STATUS_INVALID_LEVEL;
7537 status = smb_posix_open(conn, req,
7538 ppdata,
7539 total_data,
7540 smb_fname,
7541 &data_return_size);
7542 break;
7545 case SMB_POSIX_PATH_UNLINK:
7547 if (fsp) {
7548 /* We must have a pathname for this. */
7549 return NT_STATUS_INVALID_LEVEL;
7552 status = smb_posix_unlink(conn, req,
7553 pdata,
7554 total_data,
7555 smb_fname);
7556 break;
7559 default:
7560 return NT_STATUS_INVALID_LEVEL;
7563 if (!NT_STATUS_IS_OK(status)) {
7564 return status;
7567 *ret_data_size = data_return_size;
7568 return NT_STATUS_OK;
7571 /****************************************************************************
7572 Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname).
7573 ****************************************************************************/
7575 static void call_trans2setfilepathinfo(connection_struct *conn,
7576 struct smb_request *req,
7577 unsigned int tran_call,
7578 char **pparams, int total_params,
7579 char **ppdata, int total_data,
7580 unsigned int max_data_bytes)
7582 char *params = *pparams;
7583 char *pdata = *ppdata;
7584 uint16 info_level;
7585 struct smb_filename *smb_fname = NULL;
7586 files_struct *fsp = NULL;
7587 NTSTATUS status = NT_STATUS_OK;
7588 int data_return_size = 0;
7590 if (!params) {
7591 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7592 return;
7595 if (tran_call == TRANSACT2_SETFILEINFO) {
7596 if (total_params < 4) {
7597 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7598 return;
7601 fsp = file_fsp(req, SVAL(params,0));
7602 /* Basic check for non-null fsp. */
7603 if (!check_fsp_open(conn, req, fsp)) {
7604 return;
7606 info_level = SVAL(params,2);
7608 status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
7609 &smb_fname);
7610 if (!NT_STATUS_IS_OK(status)) {
7611 reply_nterror(req, status);
7612 return;
7615 if(fsp->is_directory || fsp->fh->fd == -1) {
7617 * This is actually a SETFILEINFO on a directory
7618 * handle (returned from an NT SMB). NT5.0 seems
7619 * to do this call. JRA.
7621 if (INFO_LEVEL_IS_UNIX(info_level)) {
7622 /* Always do lstat for UNIX calls. */
7623 if (SMB_VFS_LSTAT(conn, smb_fname)) {
7624 DEBUG(3,("call_trans2setfilepathinfo: "
7625 "SMB_VFS_LSTAT of %s failed "
7626 "(%s)\n",
7627 smb_fname_str_dbg(smb_fname),
7628 strerror(errno)));
7629 reply_nterror(req, map_nt_error_from_unix(errno));
7630 return;
7632 } else {
7633 if (SMB_VFS_STAT(conn, smb_fname) != 0) {
7634 DEBUG(3,("call_trans2setfilepathinfo: "
7635 "fileinfo of %s failed (%s)\n",
7636 smb_fname_str_dbg(smb_fname),
7637 strerror(errno)));
7638 reply_nterror(req, map_nt_error_from_unix(errno));
7639 return;
7642 } else if (fsp->print_file) {
7644 * Doing a DELETE_ON_CLOSE should cancel a print job.
7646 if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
7647 fsp->fh->private_options |= FILE_DELETE_ON_CLOSE;
7649 DEBUG(3,("call_trans2setfilepathinfo: "
7650 "Cancelling print job (%s)\n",
7651 fsp_str_dbg(fsp)));
7653 SSVAL(params,0,0);
7654 send_trans2_replies(conn, req, params, 2,
7655 *ppdata, 0,
7656 max_data_bytes);
7657 return;
7658 } else {
7659 reply_doserror(req, ERRDOS, ERRbadpath);
7660 return;
7662 } else {
7664 * Original code - this is an open file.
7666 if (!check_fsp(conn, req, fsp)) {
7667 return;
7670 if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
7671 DEBUG(3,("call_trans2setfilepathinfo: fstat "
7672 "of fnum %d failed (%s)\n", fsp->fnum,
7673 strerror(errno)));
7674 reply_nterror(req, map_nt_error_from_unix(errno));
7675 return;
7678 } else {
7679 char *fname = NULL;
7681 /* set path info */
7682 if (total_params < 7) {
7683 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7684 return;
7687 info_level = SVAL(params,0);
7688 srvstr_get_path(req, params, req->flags2, &fname, &params[6],
7689 total_params - 6, STR_TERMINATE,
7690 &status);
7691 if (!NT_STATUS_IS_OK(status)) {
7692 reply_nterror(req, status);
7693 return;
7696 status = filename_convert(req, conn,
7697 req->flags2 & FLAGS2_DFS_PATHNAMES,
7698 fname,
7700 NULL,
7701 &smb_fname);
7702 if (!NT_STATUS_IS_OK(status)) {
7703 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7704 reply_botherror(req,
7705 NT_STATUS_PATH_NOT_COVERED,
7706 ERRSRV, ERRbadpath);
7707 return;
7709 reply_nterror(req, status);
7710 return;
7713 if (INFO_LEVEL_IS_UNIX(info_level)) {
7715 * For CIFS UNIX extensions the target name may not exist.
7718 /* Always do lstat for UNIX calls. */
7719 SMB_VFS_LSTAT(conn, smb_fname);
7721 } else if (!VALID_STAT(smb_fname->st) &&
7722 SMB_VFS_STAT(conn, smb_fname)) {
7723 DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of "
7724 "%s failed (%s)\n",
7725 smb_fname_str_dbg(smb_fname),
7726 strerror(errno)));
7727 reply_nterror(req, map_nt_error_from_unix(errno));
7728 return;
7732 DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d "
7733 "totdata=%d\n", tran_call, smb_fname_str_dbg(smb_fname),
7734 fsp ? fsp->fnum : -1, info_level,total_data));
7736 /* Realloc the parameter size */
7737 *pparams = (char *)SMB_REALLOC(*pparams,2);
7738 if (*pparams == NULL) {
7739 reply_nterror(req, NT_STATUS_NO_MEMORY);
7740 return;
7742 params = *pparams;
7744 SSVAL(params,0,0);
7746 status = smbd_do_setfilepathinfo(conn, req, req,
7747 info_level,
7748 fsp,
7749 smb_fname,
7750 ppdata, total_data,
7751 &data_return_size);
7752 if (!NT_STATUS_IS_OK(status)) {
7753 if (open_was_deferred(req->mid)) {
7754 /* We have re-scheduled this call. */
7755 return;
7757 if (blocking_lock_was_deferred(req->mid)) {
7758 /* We have re-scheduled this call. */
7759 return;
7761 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7762 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7763 ERRSRV, ERRbadpath);
7764 return;
7766 if (info_level == SMB_POSIX_PATH_OPEN) {
7767 reply_openerror(req, status);
7768 return;
7771 reply_nterror(req, status);
7772 return;
7775 send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size,
7776 max_data_bytes);
7778 return;
7781 /****************************************************************************
7782 Reply to a TRANS2_MKDIR (make directory with extended attributes).
7783 ****************************************************************************/
7785 static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
7786 char **pparams, int total_params,
7787 char **ppdata, int total_data,
7788 unsigned int max_data_bytes)
7790 struct smb_filename *smb_dname = NULL;
7791 char *params = *pparams;
7792 char *pdata = *ppdata;
7793 char *directory = NULL;
7794 NTSTATUS status = NT_STATUS_OK;
7795 struct ea_list *ea_list = NULL;
7796 TALLOC_CTX *ctx = talloc_tos();
7798 if (!CAN_WRITE(conn)) {
7799 reply_doserror(req, ERRSRV, ERRaccess);
7800 return;
7803 if (total_params < 5) {
7804 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7805 return;
7808 srvstr_get_path(ctx, params, req->flags2, &directory, &params[4],
7809 total_params - 4, STR_TERMINATE,
7810 &status);
7811 if (!NT_STATUS_IS_OK(status)) {
7812 reply_nterror(req, status);
7813 return;
7816 DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
7818 status = filename_convert(ctx,
7819 conn,
7820 req->flags2 & FLAGS2_DFS_PATHNAMES,
7821 directory,
7823 NULL,
7824 &smb_dname);
7826 if (!NT_STATUS_IS_OK(status)) {
7827 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7828 reply_botherror(req,
7829 NT_STATUS_PATH_NOT_COVERED,
7830 ERRSRV, ERRbadpath);
7831 return;
7833 reply_nterror(req, status);
7834 return;
7837 /* Any data in this call is an EA list. */
7838 if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
7839 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
7840 goto out;
7844 * OS/2 workplace shell seems to send SET_EA requests of "null"
7845 * length (4 bytes containing IVAL 4).
7846 * They seem to have no effect. Bug #3212. JRA.
7849 if (total_data != 4) {
7850 if (total_data < 10) {
7851 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7852 goto out;
7855 if (IVAL(pdata,0) > total_data) {
7856 DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
7857 IVAL(pdata,0), (unsigned int)total_data));
7858 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7859 goto out;
7862 ea_list = read_ea_list(talloc_tos(), pdata + 4,
7863 total_data - 4);
7864 if (!ea_list) {
7865 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7866 goto out;
7869 /* If total_data == 4 Windows doesn't care what values
7870 * are placed in that field, it just ignores them.
7871 * The System i QNTC IBM SMB client puts bad values here,
7872 * so ignore them. */
7874 status = create_directory(conn, req, smb_dname);
7876 if (!NT_STATUS_IS_OK(status)) {
7877 reply_nterror(req, status);
7878 goto out;
7881 /* Try and set any given EA. */
7882 if (ea_list) {
7883 status = set_ea(conn, NULL, smb_dname, ea_list);
7884 if (!NT_STATUS_IS_OK(status)) {
7885 reply_nterror(req, status);
7886 goto out;
7890 /* Realloc the parameter and data sizes */
7891 *pparams = (char *)SMB_REALLOC(*pparams,2);
7892 if(*pparams == NULL) {
7893 reply_nterror(req, NT_STATUS_NO_MEMORY);
7894 goto out;
7896 params = *pparams;
7898 SSVAL(params,0,0);
7900 send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes);
7902 out:
7903 TALLOC_FREE(smb_dname);
7904 return;
7907 /****************************************************************************
7908 Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
7909 We don't actually do this - we just send a null response.
7910 ****************************************************************************/
7912 static void call_trans2findnotifyfirst(connection_struct *conn,
7913 struct smb_request *req,
7914 char **pparams, int total_params,
7915 char **ppdata, int total_data,
7916 unsigned int max_data_bytes)
7918 char *params = *pparams;
7919 uint16 info_level;
7921 if (total_params < 6) {
7922 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7923 return;
7926 info_level = SVAL(params,4);
7927 DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
7929 switch (info_level) {
7930 case 1:
7931 case 2:
7932 break;
7933 default:
7934 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
7935 return;
7938 /* Realloc the parameter and data sizes */
7939 *pparams = (char *)SMB_REALLOC(*pparams,6);
7940 if (*pparams == NULL) {
7941 reply_nterror(req, NT_STATUS_NO_MEMORY);
7942 return;
7944 params = *pparams;
7946 SSVAL(params,0,fnf_handle);
7947 SSVAL(params,2,0); /* No changes */
7948 SSVAL(params,4,0); /* No EA errors */
7950 fnf_handle++;
7952 if(fnf_handle == 0)
7953 fnf_handle = 257;
7955 send_trans2_replies(conn, req, params, 6, *ppdata, 0, max_data_bytes);
7957 return;
7960 /****************************************************************************
7961 Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
7962 changes). Currently this does nothing.
7963 ****************************************************************************/
7965 static void call_trans2findnotifynext(connection_struct *conn,
7966 struct smb_request *req,
7967 char **pparams, int total_params,
7968 char **ppdata, int total_data,
7969 unsigned int max_data_bytes)
7971 char *params = *pparams;
7973 DEBUG(3,("call_trans2findnotifynext\n"));
7975 /* Realloc the parameter and data sizes */
7976 *pparams = (char *)SMB_REALLOC(*pparams,4);
7977 if (*pparams == NULL) {
7978 reply_nterror(req, NT_STATUS_NO_MEMORY);
7979 return;
7981 params = *pparams;
7983 SSVAL(params,0,0); /* No changes */
7984 SSVAL(params,2,0); /* No EA errors */
7986 send_trans2_replies(conn, req, params, 4, *ppdata, 0, max_data_bytes);
7988 return;
7991 /****************************************************************************
7992 Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
7993 ****************************************************************************/
7995 static void call_trans2getdfsreferral(connection_struct *conn,
7996 struct smb_request *req,
7997 char **pparams, int total_params,
7998 char **ppdata, int total_data,
7999 unsigned int max_data_bytes)
8001 char *params = *pparams;
8002 char *pathname = NULL;
8003 int reply_size = 0;
8004 int max_referral_level;
8005 NTSTATUS status = NT_STATUS_OK;
8006 TALLOC_CTX *ctx = talloc_tos();
8008 DEBUG(10,("call_trans2getdfsreferral\n"));
8010 if (total_params < 3) {
8011 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8012 return;
8015 max_referral_level = SVAL(params,0);
8017 if(!lp_host_msdfs()) {
8018 reply_doserror(req, ERRDOS, ERRbadfunc);
8019 return;
8022 srvstr_pull_talloc(ctx, params, req->flags2, &pathname, &params[2],
8023 total_params - 2, STR_TERMINATE);
8024 if (!pathname) {
8025 reply_nterror(req, NT_STATUS_NOT_FOUND);
8026 return;
8028 if((reply_size = setup_dfs_referral(conn, pathname, max_referral_level,
8029 ppdata,&status)) < 0) {
8030 reply_nterror(req, status);
8031 return;
8034 SSVAL(req->inbuf, smb_flg2,
8035 SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
8036 send_trans2_replies(conn, req,0,0,*ppdata,reply_size, max_data_bytes);
8038 return;
8041 #define LMCAT_SPL 0x53
8042 #define LMFUNC_GETJOBID 0x60
8044 /****************************************************************************
8045 Reply to a TRANS2_IOCTL - used for OS/2 printing.
8046 ****************************************************************************/
8048 static void call_trans2ioctl(connection_struct *conn,
8049 struct smb_request *req,
8050 char **pparams, int total_params,
8051 char **ppdata, int total_data,
8052 unsigned int max_data_bytes)
8054 char *pdata = *ppdata;
8055 files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
8057 /* check for an invalid fid before proceeding */
8059 if (!fsp) {
8060 reply_doserror(req, ERRDOS, ERRbadfid);
8061 return;
8064 if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
8065 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
8066 *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
8067 if (*ppdata == NULL) {
8068 reply_nterror(req, NT_STATUS_NO_MEMORY);
8069 return;
8071 pdata = *ppdata;
8073 /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
8074 CAN ACCEPT THIS IN UNICODE. JRA. */
8076 SSVAL(pdata,0,fsp->rap_print_jobid); /* Job number */
8077 srvstr_push(pdata, req->flags2, pdata + 2,
8078 global_myname(), 15,
8079 STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */
8080 srvstr_push(pdata, req->flags2, pdata+18,
8081 lp_servicename(SNUM(conn)), 13,
8082 STR_ASCII|STR_TERMINATE); /* Service name */
8083 send_trans2_replies(conn, req, *pparams, 0, *ppdata, 32,
8084 max_data_bytes);
8085 return;
8088 DEBUG(2,("Unknown TRANS2_IOCTL\n"));
8089 reply_doserror(req, ERRSRV, ERRerror);
8092 /****************************************************************************
8093 Reply to a SMBfindclose (stop trans2 directory search).
8094 ****************************************************************************/
8096 void reply_findclose(struct smb_request *req)
8098 int dptr_num;
8099 struct smbd_server_connection *sconn = smbd_server_conn;
8101 START_PROFILE(SMBfindclose);
8103 if (req->wct < 1) {
8104 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8105 END_PROFILE(SMBfindclose);
8106 return;
8109 dptr_num = SVALS(req->vwv+0, 0);
8111 DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
8113 dptr_close(sconn, &dptr_num);
8115 reply_outbuf(req, 0, 0);
8117 DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));
8119 END_PROFILE(SMBfindclose);
8120 return;
8123 /****************************************************************************
8124 Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search).
8125 ****************************************************************************/
8127 void reply_findnclose(struct smb_request *req)
8129 int dptr_num;
8131 START_PROFILE(SMBfindnclose);
8133 if (req->wct < 1) {
8134 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8135 END_PROFILE(SMBfindnclose);
8136 return;
8139 dptr_num = SVAL(req->vwv+0, 0);
8141 DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num));
8143 /* We never give out valid handles for a
8144 findnotifyfirst - so any dptr_num is ok here.
8145 Just ignore it. */
8147 reply_outbuf(req, 0, 0);
8149 DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));
8151 END_PROFILE(SMBfindnclose);
8152 return;
8155 static void handle_trans2(connection_struct *conn, struct smb_request *req,
8156 struct trans_state *state)
8158 if (Protocol >= PROTOCOL_NT1) {
8159 req->flags2 |= 0x40; /* IS_LONG_NAME */
8160 SSVAL(req->inbuf,smb_flg2,req->flags2);
8163 if (conn->encrypt_level == Required && !req->encrypted) {
8164 if (state->call != TRANSACT2_QFSINFO &&
8165 state->call != TRANSACT2_SETFSINFO) {
8166 DEBUG(0,("handle_trans2: encryption required "
8167 "with call 0x%x\n",
8168 (unsigned int)state->call));
8169 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8170 return;
8174 SMB_PERFCOUNT_SET_SUBOP(&req->pcd, state->call);
8176 /* Now we must call the relevant TRANS2 function */
8177 switch(state->call) {
8178 case TRANSACT2_OPEN:
8180 START_PROFILE(Trans2_open);
8181 call_trans2open(conn, req,
8182 &state->param, state->total_param,
8183 &state->data, state->total_data,
8184 state->max_data_return);
8185 END_PROFILE(Trans2_open);
8186 break;
8189 case TRANSACT2_FINDFIRST:
8191 START_PROFILE(Trans2_findfirst);
8192 call_trans2findfirst(conn, req,
8193 &state->param, state->total_param,
8194 &state->data, state->total_data,
8195 state->max_data_return);
8196 END_PROFILE(Trans2_findfirst);
8197 break;
8200 case TRANSACT2_FINDNEXT:
8202 START_PROFILE(Trans2_findnext);
8203 call_trans2findnext(conn, req,
8204 &state->param, state->total_param,
8205 &state->data, state->total_data,
8206 state->max_data_return);
8207 END_PROFILE(Trans2_findnext);
8208 break;
8211 case TRANSACT2_QFSINFO:
8213 START_PROFILE(Trans2_qfsinfo);
8214 call_trans2qfsinfo(conn, req,
8215 &state->param, state->total_param,
8216 &state->data, state->total_data,
8217 state->max_data_return);
8218 END_PROFILE(Trans2_qfsinfo);
8219 break;
8222 case TRANSACT2_SETFSINFO:
8224 START_PROFILE(Trans2_setfsinfo);
8225 call_trans2setfsinfo(conn, req,
8226 &state->param, state->total_param,
8227 &state->data, state->total_data,
8228 state->max_data_return);
8229 END_PROFILE(Trans2_setfsinfo);
8230 break;
8233 case TRANSACT2_QPATHINFO:
8234 case TRANSACT2_QFILEINFO:
8236 START_PROFILE(Trans2_qpathinfo);
8237 call_trans2qfilepathinfo(conn, req, state->call,
8238 &state->param, state->total_param,
8239 &state->data, state->total_data,
8240 state->max_data_return);
8241 END_PROFILE(Trans2_qpathinfo);
8242 break;
8245 case TRANSACT2_SETPATHINFO:
8246 case TRANSACT2_SETFILEINFO:
8248 START_PROFILE(Trans2_setpathinfo);
8249 call_trans2setfilepathinfo(conn, req, state->call,
8250 &state->param, state->total_param,
8251 &state->data, state->total_data,
8252 state->max_data_return);
8253 END_PROFILE(Trans2_setpathinfo);
8254 break;
8257 case TRANSACT2_FINDNOTIFYFIRST:
8259 START_PROFILE(Trans2_findnotifyfirst);
8260 call_trans2findnotifyfirst(conn, req,
8261 &state->param, state->total_param,
8262 &state->data, state->total_data,
8263 state->max_data_return);
8264 END_PROFILE(Trans2_findnotifyfirst);
8265 break;
8268 case TRANSACT2_FINDNOTIFYNEXT:
8270 START_PROFILE(Trans2_findnotifynext);
8271 call_trans2findnotifynext(conn, req,
8272 &state->param, state->total_param,
8273 &state->data, state->total_data,
8274 state->max_data_return);
8275 END_PROFILE(Trans2_findnotifynext);
8276 break;
8279 case TRANSACT2_MKDIR:
8281 START_PROFILE(Trans2_mkdir);
8282 call_trans2mkdir(conn, req,
8283 &state->param, state->total_param,
8284 &state->data, state->total_data,
8285 state->max_data_return);
8286 END_PROFILE(Trans2_mkdir);
8287 break;
8290 case TRANSACT2_GET_DFS_REFERRAL:
8292 START_PROFILE(Trans2_get_dfs_referral);
8293 call_trans2getdfsreferral(conn, req,
8294 &state->param, state->total_param,
8295 &state->data, state->total_data,
8296 state->max_data_return);
8297 END_PROFILE(Trans2_get_dfs_referral);
8298 break;
8301 case TRANSACT2_IOCTL:
8303 START_PROFILE(Trans2_ioctl);
8304 call_trans2ioctl(conn, req,
8305 &state->param, state->total_param,
8306 &state->data, state->total_data,
8307 state->max_data_return);
8308 END_PROFILE(Trans2_ioctl);
8309 break;
8312 default:
8313 /* Error in request */
8314 DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
8315 reply_doserror(req, ERRSRV,ERRerror);
8319 /****************************************************************************
8320 Reply to a SMBtrans2.
8321 ****************************************************************************/
8323 void reply_trans2(struct smb_request *req)
8325 connection_struct *conn = req->conn;
8326 unsigned int dsoff;
8327 unsigned int dscnt;
8328 unsigned int psoff;
8329 unsigned int pscnt;
8330 unsigned int tran_call;
8331 struct trans_state *state;
8332 NTSTATUS result;
8334 START_PROFILE(SMBtrans2);
8336 if (req->wct < 14) {
8337 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8338 END_PROFILE(SMBtrans2);
8339 return;
8342 dsoff = SVAL(req->vwv+12, 0);
8343 dscnt = SVAL(req->vwv+11, 0);
8344 psoff = SVAL(req->vwv+10, 0);
8345 pscnt = SVAL(req->vwv+9, 0);
8346 tran_call = SVAL(req->vwv+14, 0);
8348 result = allow_new_trans(conn->pending_trans, req->mid);
8349 if (!NT_STATUS_IS_OK(result)) {
8350 DEBUG(2, ("Got invalid trans2 request: %s\n",
8351 nt_errstr(result)));
8352 reply_nterror(req, result);
8353 END_PROFILE(SMBtrans2);
8354 return;
8357 if (IS_IPC(conn)) {
8358 switch (tran_call) {
8359 /* List the allowed trans2 calls on IPC$ */
8360 case TRANSACT2_OPEN:
8361 case TRANSACT2_GET_DFS_REFERRAL:
8362 case TRANSACT2_QFILEINFO:
8363 case TRANSACT2_QFSINFO:
8364 case TRANSACT2_SETFSINFO:
8365 break;
8366 default:
8367 reply_doserror(req, ERRSRV, ERRaccess);
8368 END_PROFILE(SMBtrans2);
8369 return;
8373 if ((state = TALLOC_P(conn, struct trans_state)) == NULL) {
8374 DEBUG(0, ("talloc failed\n"));
8375 reply_nterror(req, NT_STATUS_NO_MEMORY);
8376 END_PROFILE(SMBtrans2);
8377 return;
8380 state->cmd = SMBtrans2;
8382 state->mid = req->mid;
8383 state->vuid = req->vuid;
8384 state->setup_count = SVAL(req->vwv+13, 0);
8385 state->setup = NULL;
8386 state->total_param = SVAL(req->vwv+0, 0);
8387 state->param = NULL;
8388 state->total_data = SVAL(req->vwv+1, 0);
8389 state->data = NULL;
8390 state->max_param_return = SVAL(req->vwv+2, 0);
8391 state->max_data_return = SVAL(req->vwv+3, 0);
8392 state->max_setup_return = SVAL(req->vwv+4, 0);
8393 state->close_on_completion = BITSETW(req->vwv+5, 0);
8394 state->one_way = BITSETW(req->vwv+5, 1);
8396 state->call = tran_call;
8398 /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
8399 is so as a sanity check */
8400 if (state->setup_count != 1) {
8402 * Need to have rc=0 for ioctl to get job id for OS/2.
8403 * Network printing will fail if function is not successful.
8404 * Similar function in reply.c will be used if protocol
8405 * is LANMAN1.0 instead of LM1.2X002.
8406 * Until DosPrintSetJobInfo with PRJINFO3 is supported,
8407 * outbuf doesn't have to be set(only job id is used).
8409 if ( (state->setup_count == 4)
8410 && (tran_call == TRANSACT2_IOCTL)
8411 && (SVAL(req->vwv+16, 0) == LMCAT_SPL)
8412 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
8413 DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
8414 } else {
8415 DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
8416 DEBUG(2,("Transaction is %d\n",tran_call));
8417 TALLOC_FREE(state);
8418 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8419 END_PROFILE(SMBtrans2);
8420 return;
8424 if ((dscnt > state->total_data) || (pscnt > state->total_param))
8425 goto bad_param;
8427 if (state->total_data) {
8429 if (trans_oob(state->total_data, 0, dscnt)
8430 || trans_oob(smb_len(req->inbuf), dsoff, dscnt)) {
8431 goto bad_param;
8434 /* Can't use talloc here, the core routines do realloc on the
8435 * params and data. */
8436 state->data = (char *)SMB_MALLOC(state->total_data);
8437 if (state->data == NULL) {
8438 DEBUG(0,("reply_trans2: data malloc fail for %u "
8439 "bytes !\n", (unsigned int)state->total_data));
8440 TALLOC_FREE(state);
8441 reply_nterror(req, NT_STATUS_NO_MEMORY);
8442 END_PROFILE(SMBtrans2);
8443 return;
8446 memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
8449 if (state->total_param) {
8451 if (trans_oob(state->total_param, 0, pscnt)
8452 || trans_oob(smb_len(req->inbuf), psoff, pscnt)) {
8453 goto bad_param;
8456 /* Can't use talloc here, the core routines do realloc on the
8457 * params and data. */
8458 state->param = (char *)SMB_MALLOC(state->total_param);
8459 if (state->param == NULL) {
8460 DEBUG(0,("reply_trans: param malloc fail for %u "
8461 "bytes !\n", (unsigned int)state->total_param));
8462 SAFE_FREE(state->data);
8463 TALLOC_FREE(state);
8464 reply_nterror(req, NT_STATUS_NO_MEMORY);
8465 END_PROFILE(SMBtrans2);
8466 return;
8469 memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
8472 state->received_data = dscnt;
8473 state->received_param = pscnt;
8475 if ((state->received_param == state->total_param) &&
8476 (state->received_data == state->total_data)) {
8478 handle_trans2(conn, req, state);
8480 SAFE_FREE(state->data);
8481 SAFE_FREE(state->param);
8482 TALLOC_FREE(state);
8483 END_PROFILE(SMBtrans2);
8484 return;
8487 DLIST_ADD(conn->pending_trans, state);
8489 /* We need to send an interim response then receive the rest
8490 of the parameter/data bytes */
8491 reply_outbuf(req, 0, 0);
8492 show_msg((char *)req->outbuf);
8493 END_PROFILE(SMBtrans2);
8494 return;
8496 bad_param:
8498 DEBUG(0,("reply_trans2: invalid trans parameters\n"));
8499 SAFE_FREE(state->data);
8500 SAFE_FREE(state->param);
8501 TALLOC_FREE(state);
8502 END_PROFILE(SMBtrans2);
8503 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8507 /****************************************************************************
8508 Reply to a SMBtranss2
8509 ****************************************************************************/
8511 void reply_transs2(struct smb_request *req)
8513 connection_struct *conn = req->conn;
8514 unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
8515 struct trans_state *state;
8517 START_PROFILE(SMBtranss2);
8519 show_msg((char *)req->inbuf);
8521 if (req->wct < 8) {
8522 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8523 END_PROFILE(SMBtranss2);
8524 return;
8527 for (state = conn->pending_trans; state != NULL;
8528 state = state->next) {
8529 if (state->mid == req->mid) {
8530 break;
8534 if ((state == NULL) || (state->cmd != SMBtrans2)) {
8535 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8536 END_PROFILE(SMBtranss2);
8537 return;
8540 /* Revise state->total_param and state->total_data in case they have
8541 changed downwards */
8543 if (SVAL(req->vwv+0, 0) < state->total_param)
8544 state->total_param = SVAL(req->vwv+0, 0);
8545 if (SVAL(req->vwv+1, 0) < state->total_data)
8546 state->total_data = SVAL(req->vwv+1, 0);
8548 pcnt = SVAL(req->vwv+2, 0);
8549 poff = SVAL(req->vwv+3, 0);
8550 pdisp = SVAL(req->vwv+4, 0);
8552 dcnt = SVAL(req->vwv+5, 0);
8553 doff = SVAL(req->vwv+6, 0);
8554 ddisp = SVAL(req->vwv+7, 0);
8556 state->received_param += pcnt;
8557 state->received_data += dcnt;
8559 if ((state->received_data > state->total_data) ||
8560 (state->received_param > state->total_param))
8561 goto bad_param;
8563 if (pcnt) {
8564 if (trans_oob(state->total_param, pdisp, pcnt)
8565 || trans_oob(smb_len(req->inbuf), poff, pcnt)) {
8566 goto bad_param;
8568 memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
8571 if (dcnt) {
8572 if (trans_oob(state->total_data, ddisp, dcnt)
8573 || trans_oob(smb_len(req->inbuf), doff, dcnt)) {
8574 goto bad_param;
8576 memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
8579 if ((state->received_param < state->total_param) ||
8580 (state->received_data < state->total_data)) {
8581 END_PROFILE(SMBtranss2);
8582 return;
8585 handle_trans2(conn, req, state);
8587 DLIST_REMOVE(conn->pending_trans, state);
8588 SAFE_FREE(state->data);
8589 SAFE_FREE(state->param);
8590 TALLOC_FREE(state);
8592 END_PROFILE(SMBtranss2);
8593 return;
8595 bad_param:
8597 DEBUG(0,("reply_transs2: invalid trans parameters\n"));
8598 DLIST_REMOVE(conn->pending_trans, state);
8599 SAFE_FREE(state->data);
8600 SAFE_FREE(state->param);
8601 TALLOC_FREE(state);
8602 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8603 END_PROFILE(SMBtranss2);
8604 return;