s4:dcesrv_samr: always use mem_ctx as initial parent for samr_*_state
[Samba.git] / source3 / smbd / trans2.c
blobce458126d3cc9d9765fc30b0145aacaee0700be1
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 NULL
79 int i;
81 for (i = 0; prohibited_ea_names[i]; i++) {
82 if (strequal( prohibited_ea_names[i], unix_ea_name))
83 return true;
85 if (StrnCaseCmp(unix_ea_name, SAMBA_XATTR_DOSSTREAM_PREFIX,
86 strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) == 0) {
87 return true;
89 return false;
92 /****************************************************************************
93 Get one EA value. Fill in a struct ea_struct.
94 ****************************************************************************/
96 NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn,
97 files_struct *fsp, const char *fname,
98 const char *ea_name, struct ea_struct *pea)
100 /* Get the value of this xattr. Max size is 64k. */
101 size_t attr_size = 256;
102 char *val = NULL;
103 ssize_t sizeret;
105 again:
107 val = TALLOC_REALLOC_ARRAY(mem_ctx, val, char, attr_size);
108 if (!val) {
109 return NT_STATUS_NO_MEMORY;
112 if (fsp && fsp->fh->fd != -1) {
113 sizeret = SMB_VFS_FGETXATTR(fsp, ea_name, val, attr_size);
114 } else {
115 sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size);
118 if (sizeret == -1 && errno == ERANGE && attr_size != 65536) {
119 attr_size = 65536;
120 goto again;
123 if (sizeret == -1) {
124 return map_nt_error_from_unix(errno);
127 DEBUG(10,("get_ea_value: EA %s is of length %u\n", ea_name, (unsigned int)sizeret));
128 dump_data(10, (uint8 *)val, sizeret);
130 pea->flags = 0;
131 if (strnequal(ea_name, "user.", 5)) {
132 pea->name = talloc_strdup(mem_ctx, &ea_name[5]);
133 } else {
134 pea->name = talloc_strdup(mem_ctx, ea_name);
136 if (pea->name == NULL) {
137 TALLOC_FREE(val);
138 return NT_STATUS_NO_MEMORY;
140 pea->value.data = (unsigned char *)val;
141 pea->value.length = (size_t)sizeret;
142 return NT_STATUS_OK;
145 NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
146 files_struct *fsp, const char *fname,
147 char ***pnames, size_t *pnum_names)
149 /* Get a list of all xattrs. Max namesize is 64k. */
150 size_t ea_namelist_size = 1024;
151 char *ea_namelist = NULL;
153 char *p;
154 char **names, **tmp;
155 size_t num_names;
156 ssize_t sizeret = -1;
158 if (!lp_ea_support(SNUM(conn))) {
159 if (pnames) {
160 *pnames = NULL;
162 *pnum_names = 0;
163 return NT_STATUS_OK;
167 * TALLOC the result early to get the talloc hierarchy right.
170 names = TALLOC_ARRAY(mem_ctx, char *, 1);
171 if (names == NULL) {
172 DEBUG(0, ("talloc failed\n"));
173 return NT_STATUS_NO_MEMORY;
176 while (ea_namelist_size <= 65536) {
178 ea_namelist = TALLOC_REALLOC_ARRAY(
179 names, ea_namelist, char, ea_namelist_size);
180 if (ea_namelist == NULL) {
181 DEBUG(0, ("talloc failed\n"));
182 TALLOC_FREE(names);
183 return NT_STATUS_NO_MEMORY;
186 if (fsp && fsp->fh->fd != -1) {
187 sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
188 ea_namelist_size);
189 } else {
190 sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist,
191 ea_namelist_size);
194 if ((sizeret == -1) && (errno == ERANGE)) {
195 ea_namelist_size *= 2;
197 else {
198 break;
202 if (sizeret == -1) {
203 TALLOC_FREE(names);
204 return map_nt_error_from_unix(errno);
207 DEBUG(10, ("get_ea_list_from_file: ea_namelist size = %u\n",
208 (unsigned int)sizeret));
210 if (sizeret == 0) {
211 TALLOC_FREE(names);
212 if (pnames) {
213 *pnames = NULL;
215 *pnum_names = 0;
216 return NT_STATUS_OK;
220 * Ensure the result is 0-terminated
223 if (ea_namelist[sizeret-1] != '\0') {
224 TALLOC_FREE(names);
225 return NT_STATUS_INTERNAL_ERROR;
229 * count the names
231 num_names = 0;
233 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
234 num_names += 1;
237 tmp = TALLOC_REALLOC_ARRAY(mem_ctx, names, char *, num_names);
238 if (tmp == NULL) {
239 DEBUG(0, ("talloc failed\n"));
240 TALLOC_FREE(names);
241 return NT_STATUS_NO_MEMORY;
244 names = tmp;
245 num_names = 0;
247 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
248 names[num_names++] = p;
251 if (pnames) {
252 *pnames = names;
253 } else {
254 TALLOC_FREE(names);
256 *pnum_names = num_names;
257 return NT_STATUS_OK;
260 /****************************************************************************
261 Return a linked list of the total EA's. Plus the total size
262 ****************************************************************************/
264 static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
265 const char *fname, size_t *pea_total_len)
267 /* Get a list of all xattrs. Max namesize is 64k. */
268 size_t i, num_names;
269 char **names;
270 struct ea_list *ea_list_head = NULL;
271 NTSTATUS status;
273 *pea_total_len = 0;
275 if (!lp_ea_support(SNUM(conn))) {
276 return NULL;
279 status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
280 &names, &num_names);
282 if (!NT_STATUS_IS_OK(status) || (num_names == 0)) {
283 return NULL;
286 for (i=0; i<num_names; i++) {
287 struct ea_list *listp;
288 fstring dos_ea_name;
290 if (strnequal(names[i], "system.", 7)
291 || samba_private_attr_name(names[i]))
292 continue;
294 listp = TALLOC_P(mem_ctx, struct ea_list);
295 if (listp == NULL) {
296 return NULL;
299 if (!NT_STATUS_IS_OK(get_ea_value(mem_ctx, conn, fsp,
300 fname, names[i],
301 &listp->ea))) {
302 return NULL;
305 push_ascii_fstring(dos_ea_name, listp->ea.name);
307 *pea_total_len +=
308 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
310 DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len "
311 "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
312 (unsigned int)listp->ea.value.length));
314 DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
318 /* Add on 4 for total length. */
319 if (*pea_total_len) {
320 *pea_total_len += 4;
323 DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
324 (unsigned int)*pea_total_len));
326 return ea_list_head;
329 /****************************************************************************
330 Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer
331 that was filled.
332 ****************************************************************************/
334 static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
335 connection_struct *conn, struct ea_list *ea_list)
337 unsigned int ret_data_size = 4;
338 char *p = pdata;
340 SMB_ASSERT(total_data_size >= 4);
342 if (!lp_ea_support(SNUM(conn))) {
343 SIVAL(pdata,4,0);
344 return 4;
347 for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
348 size_t dos_namelen;
349 fstring dos_ea_name;
350 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
351 dos_namelen = strlen(dos_ea_name);
352 if (dos_namelen > 255 || dos_namelen == 0) {
353 break;
355 if (ea_list->ea.value.length > 65535) {
356 break;
358 if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
359 break;
362 /* We know we have room. */
363 SCVAL(p,0,ea_list->ea.flags);
364 SCVAL(p,1,dos_namelen);
365 SSVAL(p,2,ea_list->ea.value.length);
366 fstrcpy(p+4, dos_ea_name);
367 memcpy( p + 4 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
369 total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
370 p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
373 ret_data_size = PTR_DIFF(p, pdata);
374 DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
375 SIVAL(pdata,0,ret_data_size);
376 return ret_data_size;
379 static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
380 char *pdata,
381 unsigned int total_data_size,
382 unsigned int *ret_data_size,
383 connection_struct *conn,
384 struct ea_list *ea_list)
386 uint8_t *p = (uint8_t *)pdata;
387 uint8_t *last_start = NULL;
389 *ret_data_size = 0;
391 if (!lp_ea_support(SNUM(conn))) {
392 return NT_STATUS_NO_EAS_ON_FILE;
395 for (; ea_list; ea_list = ea_list->next) {
396 size_t dos_namelen;
397 fstring dos_ea_name;
398 size_t this_size;
400 if (last_start) {
401 SIVAL(last_start, 0, PTR_DIFF(p, last_start));
403 last_start = p;
405 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
406 dos_namelen = strlen(dos_ea_name);
407 if (dos_namelen > 255 || dos_namelen == 0) {
408 return NT_STATUS_INTERNAL_ERROR;
410 if (ea_list->ea.value.length > 65535) {
411 return NT_STATUS_INTERNAL_ERROR;
414 this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length;
416 if (ea_list->next) {
417 size_t pad = 4 - (this_size % 4);
418 this_size += pad;
421 if (this_size > total_data_size) {
422 return NT_STATUS_INFO_LENGTH_MISMATCH;
425 /* We know we have room. */
426 SIVAL(p, 0x00, 0); /* next offset */
427 SCVAL(p, 0x04, ea_list->ea.flags);
428 SCVAL(p, 0x05, dos_namelen);
429 SSVAL(p, 0x06, ea_list->ea.value.length);
430 fstrcpy((char *)(p+0x08), dos_ea_name);
431 memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
433 total_data_size -= this_size;
434 p += this_size;
437 *ret_data_size = PTR_DIFF(p, pdata);
438 DEBUG(10,("fill_ea_chained_buffer: data_size = %u\n", *ret_data_size));
439 return NT_STATUS_OK;
442 static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname)
444 size_t total_ea_len = 0;
445 TALLOC_CTX *mem_ctx = NULL;
447 if (!lp_ea_support(SNUM(conn))) {
448 return 0;
450 mem_ctx = talloc_tos();
451 (void)get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
452 return total_ea_len;
455 /****************************************************************************
456 Ensure the EA name is case insensitive by matching any existing EA name.
457 ****************************************************************************/
459 static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, const char *fname, fstring unix_ea_name)
461 size_t total_ea_len;
462 TALLOC_CTX *mem_ctx = talloc_tos();
463 struct ea_list *ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
465 for (; ea_list; ea_list = ea_list->next) {
466 if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
467 DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
468 &unix_ea_name[5], ea_list->ea.name));
469 safe_strcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-6);
470 break;
475 /****************************************************************************
476 Set or delete an extended attribute.
477 ****************************************************************************/
479 NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
480 const struct smb_filename *smb_fname, struct ea_list *ea_list)
482 char *fname = NULL;
484 if (!lp_ea_support(SNUM(conn))) {
485 return NT_STATUS_EAS_NOT_SUPPORTED;
488 /* For now setting EAs on streams isn't supported. */
489 fname = smb_fname->base_name;
491 for (;ea_list; ea_list = ea_list->next) {
492 int ret;
493 fstring unix_ea_name;
495 fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
496 fstrcat(unix_ea_name, ea_list->ea.name);
498 canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
500 DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
502 if (samba_private_attr_name(unix_ea_name)) {
503 DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
504 return NT_STATUS_ACCESS_DENIED;
507 if (ea_list->ea.value.length == 0) {
508 /* Remove the attribute. */
509 if (fsp && (fsp->fh->fd != -1)) {
510 DEBUG(10,("set_ea: deleting ea name %s on "
511 "file %s by file descriptor.\n",
512 unix_ea_name, fsp_str_dbg(fsp)));
513 ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name);
514 } else {
515 DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",
516 unix_ea_name, fname));
517 ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);
519 #ifdef ENOATTR
520 /* Removing a non existent attribute always succeeds. */
521 if (ret == -1 && errno == ENOATTR) {
522 DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",
523 unix_ea_name));
524 ret = 0;
526 #endif
527 } else {
528 if (fsp && (fsp->fh->fd != -1)) {
529 DEBUG(10,("set_ea: setting ea name %s on file "
530 "%s by file descriptor.\n",
531 unix_ea_name, fsp_str_dbg(fsp)));
532 ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name,
533 ea_list->ea.value.data, ea_list->ea.value.length, 0);
534 } else {
535 DEBUG(10,("set_ea: setting ea name %s on file %s.\n",
536 unix_ea_name, fname));
537 ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name,
538 ea_list->ea.value.data, ea_list->ea.value.length, 0);
542 if (ret == -1) {
543 #ifdef ENOTSUP
544 if (errno == ENOTSUP) {
545 return NT_STATUS_EAS_NOT_SUPPORTED;
547 #endif
548 return map_nt_error_from_unix(errno);
552 return NT_STATUS_OK;
554 /****************************************************************************
555 Read a list of EA names from an incoming data buffer. Create an ea_list with them.
556 ****************************************************************************/
558 static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
560 struct ea_list *ea_list_head = NULL;
561 size_t converted_size, offset = 0;
563 while (offset + 2 < data_size) {
564 struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
565 unsigned int namelen = CVAL(pdata,offset);
567 offset++; /* Go past the namelen byte. */
569 /* integer wrap paranioa. */
570 if ((offset + namelen < offset) || (offset + namelen < namelen) ||
571 (offset > data_size) || (namelen > data_size) ||
572 (offset + namelen >= data_size)) {
573 break;
575 /* Ensure the name is null terminated. */
576 if (pdata[offset + namelen] != '\0') {
577 return NULL;
579 if (!pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset],
580 &converted_size)) {
581 DEBUG(0,("read_ea_name_list: pull_ascii_talloc "
582 "failed: %s", strerror(errno)));
584 if (!eal->ea.name) {
585 return NULL;
588 offset += (namelen + 1); /* Go past the name + terminating zero. */
589 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
590 DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
593 return ea_list_head;
596 /****************************************************************************
597 Read one EA list entry from the buffer.
598 ****************************************************************************/
600 struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used)
602 struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
603 uint16 val_len;
604 unsigned int namelen;
605 size_t converted_size;
607 if (!eal) {
608 return NULL;
611 if (data_size < 6) {
612 return NULL;
615 eal->ea.flags = CVAL(pdata,0);
616 namelen = CVAL(pdata,1);
617 val_len = SVAL(pdata,2);
619 if (4 + namelen + 1 + val_len > data_size) {
620 return NULL;
623 /* Ensure the name is null terminated. */
624 if (pdata[namelen + 4] != '\0') {
625 return NULL;
627 if (!pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4, &converted_size)) {
628 DEBUG(0,("read_ea_list_entry: pull_ascii_talloc failed: %s",
629 strerror(errno)));
631 if (!eal->ea.name) {
632 return NULL;
635 eal->ea.value = data_blob_talloc(eal, NULL, (size_t)val_len + 1);
636 if (!eal->ea.value.data) {
637 return NULL;
640 memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len);
642 /* Ensure we're null terminated just in case we print the value. */
643 eal->ea.value.data[val_len] = '\0';
644 /* But don't count the null. */
645 eal->ea.value.length--;
647 if (pbytes_used) {
648 *pbytes_used = 4 + namelen + 1 + val_len;
651 DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name));
652 dump_data(10, eal->ea.value.data, eal->ea.value.length);
654 return eal;
657 /****************************************************************************
658 Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
659 ****************************************************************************/
661 static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
663 struct ea_list *ea_list_head = NULL;
664 size_t offset = 0;
665 size_t bytes_used = 0;
667 while (offset < data_size) {
668 struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);
670 if (!eal) {
671 return NULL;
674 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
675 offset += bytes_used;
678 return ea_list_head;
681 /****************************************************************************
682 Count the total EA size needed.
683 ****************************************************************************/
685 static size_t ea_list_size(struct ea_list *ealist)
687 fstring dos_ea_name;
688 struct ea_list *listp;
689 size_t ret = 0;
691 for (listp = ealist; listp; listp = listp->next) {
692 push_ascii_fstring(dos_ea_name, listp->ea.name);
693 ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
695 /* Add on 4 for total length. */
696 if (ret) {
697 ret += 4;
700 return ret;
703 /****************************************************************************
704 Return a union of EA's from a file list and a list of names.
705 The TALLOC context for the two lists *MUST* be identical as we steal
706 memory from one list to add to another. JRA.
707 ****************************************************************************/
709 static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *file_list, size_t *total_ea_len)
711 struct ea_list *nlistp, *flistp;
713 for (nlistp = name_list; nlistp; nlistp = nlistp->next) {
714 for (flistp = file_list; flistp; flistp = flistp->next) {
715 if (strequal(nlistp->ea.name, flistp->ea.name)) {
716 break;
720 if (flistp) {
721 /* Copy the data from this entry. */
722 nlistp->ea.flags = flistp->ea.flags;
723 nlistp->ea.value = flistp->ea.value;
724 } else {
725 /* Null entry. */
726 nlistp->ea.flags = 0;
727 ZERO_STRUCT(nlistp->ea.value);
731 *total_ea_len = ea_list_size(name_list);
732 return name_list;
735 /****************************************************************************
736 Send the required number of replies back.
737 We assume all fields other than the data fields are
738 set correctly for the type of call.
739 HACK ! Always assumes smb_setup field is zero.
740 ****************************************************************************/
742 void send_trans2_replies(connection_struct *conn,
743 struct smb_request *req,
744 const char *params,
745 int paramsize,
746 const char *pdata,
747 int datasize,
748 int max_data_bytes)
750 /* As we are using a protocol > LANMAN1 then the max_send
751 variable must have been set in the sessetupX call.
752 This takes precedence over the max_xmit field in the
753 global struct. These different max_xmit variables should
754 be merged as this is now too confusing */
756 int data_to_send = datasize;
757 int params_to_send = paramsize;
758 int useable_space;
759 const char *pp = params;
760 const char *pd = pdata;
761 int params_sent_thistime, data_sent_thistime, total_sent_thistime;
762 int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
763 int data_alignment_offset = 0;
764 bool overflow = False;
765 struct smbd_server_connection *sconn = smbd_server_conn;
766 int max_send = sconn->smb1.sessions.max_send;
768 /* Modify the data_to_send and datasize and set the error if
769 we're trying to send more than max_data_bytes. We still send
770 the part of the packet(s) that fit. Strange, but needed
771 for OS/2. */
773 if (max_data_bytes > 0 && datasize > max_data_bytes) {
774 DEBUG(5,("send_trans2_replies: max_data_bytes %d exceeded by data %d\n",
775 max_data_bytes, datasize ));
776 datasize = data_to_send = max_data_bytes;
777 overflow = True;
780 /* If there genuinely are no parameters or data to send just send the empty packet */
782 if(params_to_send == 0 && data_to_send == 0) {
783 reply_outbuf(req, 10, 0);
784 show_msg((char *)req->outbuf);
785 if (!srv_send_smb(smbd_server_fd(),
786 (char *)req->outbuf,
787 true, req->seqnum+1,
788 IS_CONN_ENCRYPTED(conn),
789 &req->pcd)) {
790 exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
792 TALLOC_FREE(req->outbuf);
793 return;
796 /* When sending params and data ensure that both are nicely aligned */
797 /* Only do this alignment when there is also data to send - else
798 can cause NT redirector problems. */
800 if (((params_to_send % 4) != 0) && (data_to_send != 0))
801 data_alignment_offset = 4 - (params_to_send % 4);
803 /* Space is bufsize minus Netbios over TCP header minus SMB header */
804 /* The alignment_offset is to align the param bytes on an even byte
805 boundary. NT 4.0 Beta needs this to work correctly. */
807 useable_space = max_send - (smb_size
808 + 2 * 10 /* wct */
809 + alignment_offset
810 + data_alignment_offset);
812 if (useable_space < 0) {
813 DEBUG(0, ("send_trans2_replies failed sanity useable_space "
814 "= %d!!!", useable_space));
815 exit_server_cleanly("send_trans2_replies: Not enough space");
818 while (params_to_send || data_to_send) {
819 /* Calculate whether we will totally or partially fill this packet */
821 total_sent_thistime = params_to_send + data_to_send;
823 /* We can never send more than useable_space */
825 * Note that 'useable_space' does not include the alignment offsets,
826 * but we must include the alignment offsets in the calculation of
827 * the length of the data we send over the wire, as the alignment offsets
828 * are sent here. Fix from Marc_Jacobsen@hp.com.
831 total_sent_thistime = MIN(total_sent_thistime, useable_space);
833 reply_outbuf(req, 10, total_sent_thistime + alignment_offset
834 + data_alignment_offset);
837 * We might have SMBtrans2s in req which was transferred to
838 * the outbuf, fix that.
840 SCVAL(req->outbuf, smb_com, SMBtrans2);
842 /* Set total params and data to be sent */
843 SSVAL(req->outbuf,smb_tprcnt,paramsize);
844 SSVAL(req->outbuf,smb_tdrcnt,datasize);
846 /* Calculate how many parameters and data we can fit into
847 * this packet. Parameters get precedence
850 params_sent_thistime = MIN(params_to_send,useable_space);
851 data_sent_thistime = useable_space - params_sent_thistime;
852 data_sent_thistime = MIN(data_sent_thistime,data_to_send);
854 SSVAL(req->outbuf,smb_prcnt, params_sent_thistime);
856 /* smb_proff is the offset from the start of the SMB header to the
857 parameter bytes, however the first 4 bytes of outbuf are
858 the Netbios over TCP header. Thus use smb_base() to subtract
859 them from the calculation */
861 SSVAL(req->outbuf,smb_proff,
862 ((smb_buf(req->outbuf)+alignment_offset)
863 - smb_base(req->outbuf)));
865 if(params_sent_thistime == 0)
866 SSVAL(req->outbuf,smb_prdisp,0);
867 else
868 /* Absolute displacement of param bytes sent in this packet */
869 SSVAL(req->outbuf,smb_prdisp,pp - params);
871 SSVAL(req->outbuf,smb_drcnt, data_sent_thistime);
872 if(data_sent_thistime == 0) {
873 SSVAL(req->outbuf,smb_droff,0);
874 SSVAL(req->outbuf,smb_drdisp, 0);
875 } else {
876 /* The offset of the data bytes is the offset of the
877 parameter bytes plus the number of parameters being sent this time */
878 SSVAL(req->outbuf, smb_droff,
879 ((smb_buf(req->outbuf)+alignment_offset)
880 - smb_base(req->outbuf))
881 + params_sent_thistime + data_alignment_offset);
882 SSVAL(req->outbuf,smb_drdisp, pd - pdata);
885 /* Initialize the padding for alignment */
887 if (alignment_offset != 0) {
888 memset(smb_buf(req->outbuf), 0, alignment_offset);
891 /* Copy the param bytes into the packet */
893 if(params_sent_thistime) {
894 memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
895 params_sent_thistime);
898 /* Copy in the data bytes */
899 if(data_sent_thistime) {
900 if (data_alignment_offset != 0) {
901 memset((smb_buf(req->outbuf)+alignment_offset+
902 params_sent_thistime), 0,
903 data_alignment_offset);
905 memcpy(smb_buf(req->outbuf)+alignment_offset
906 +params_sent_thistime+data_alignment_offset,
907 pd,data_sent_thistime);
910 DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
911 params_sent_thistime, data_sent_thistime, useable_space));
912 DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
913 params_to_send, data_to_send, paramsize, datasize));
915 if (overflow) {
916 error_packet_set((char *)req->outbuf,
917 ERRDOS,ERRbufferoverflow,
918 STATUS_BUFFER_OVERFLOW,
919 __LINE__,__FILE__);
922 /* Send the packet */
923 show_msg((char *)req->outbuf);
924 if (!srv_send_smb(smbd_server_fd(),
925 (char *)req->outbuf,
926 true, req->seqnum+1,
927 IS_CONN_ENCRYPTED(conn),
928 &req->pcd))
929 exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
931 TALLOC_FREE(req->outbuf);
933 pp += params_sent_thistime;
934 pd += data_sent_thistime;
936 params_to_send -= params_sent_thistime;
937 data_to_send -= data_sent_thistime;
939 /* Sanity check */
940 if(params_to_send < 0 || data_to_send < 0) {
941 DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
942 params_to_send, data_to_send));
943 return;
947 return;
950 /****************************************************************************
951 Reply to a TRANSACT2_OPEN.
952 ****************************************************************************/
954 static void call_trans2open(connection_struct *conn,
955 struct smb_request *req,
956 char **pparams, int total_params,
957 char **ppdata, int total_data,
958 unsigned int max_data_bytes)
960 struct smb_filename *smb_fname = NULL;
961 char *params = *pparams;
962 char *pdata = *ppdata;
963 int deny_mode;
964 int32 open_attr;
965 bool oplock_request;
966 #if 0
967 bool return_additional_info;
968 int16 open_sattr;
969 time_t open_time;
970 #endif
971 int open_ofun;
972 uint32 open_size;
973 char *pname;
974 char *fname = NULL;
975 SMB_OFF_T size=0;
976 int fattr=0,mtime=0;
977 SMB_INO_T inode = 0;
978 int smb_action = 0;
979 files_struct *fsp;
980 struct ea_list *ea_list = NULL;
981 uint16 flags = 0;
982 NTSTATUS status;
983 uint32 access_mask;
984 uint32 share_mode;
985 uint32 create_disposition;
986 uint32 create_options = 0;
987 TALLOC_CTX *ctx = talloc_tos();
990 * Ensure we have enough parameters to perform the operation.
993 if (total_params < 29) {
994 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
995 goto out;
998 flags = SVAL(params, 0);
999 deny_mode = SVAL(params, 2);
1000 open_attr = SVAL(params,6);
1001 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
1002 if (oplock_request) {
1003 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
1006 #if 0
1007 return_additional_info = BITSETW(params,0);
1008 open_sattr = SVAL(params, 4);
1009 open_time = make_unix_date3(params+8);
1010 #endif
1011 open_ofun = SVAL(params,12);
1012 open_size = IVAL(params,14);
1013 pname = &params[28];
1015 if (IS_IPC(conn)) {
1016 reply_doserror(req, ERRSRV, ERRaccess);
1017 goto out;
1020 srvstr_get_path(ctx, params, req->flags2, &fname, pname,
1021 total_params - 28, STR_TERMINATE,
1022 &status);
1023 if (!NT_STATUS_IS_OK(status)) {
1024 reply_nterror(req, status);
1025 goto out;
1028 DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n",
1029 fname, (unsigned int)deny_mode, (unsigned int)open_attr,
1030 (unsigned int)open_ofun, open_size));
1032 status = filename_convert(ctx,
1033 conn,
1034 req->flags2 & FLAGS2_DFS_PATHNAMES,
1035 fname,
1037 NULL,
1038 &smb_fname);
1039 if (!NT_STATUS_IS_OK(status)) {
1040 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1041 reply_botherror(req,
1042 NT_STATUS_PATH_NOT_COVERED,
1043 ERRSRV, ERRbadpath);
1044 goto out;
1046 reply_nterror(req, status);
1047 goto out;
1050 if (open_ofun == 0) {
1051 reply_nterror(req, NT_STATUS_OBJECT_NAME_COLLISION);
1052 goto out;
1055 if (!map_open_params_to_ntcreate(smb_fname, deny_mode, open_ofun,
1056 &access_mask, &share_mode,
1057 &create_disposition,
1058 &create_options)) {
1059 reply_doserror(req, ERRDOS, ERRbadaccess);
1060 goto out;
1063 /* Any data in this call is an EA list. */
1064 if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
1065 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
1066 goto out;
1069 if (total_data != 4) {
1070 if (total_data < 10) {
1071 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1072 goto out;
1075 if (IVAL(pdata,0) > total_data) {
1076 DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n",
1077 IVAL(pdata,0), (unsigned int)total_data));
1078 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1079 goto out;
1082 ea_list = read_ea_list(talloc_tos(), pdata + 4,
1083 total_data - 4);
1084 if (!ea_list) {
1085 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1086 goto out;
1088 } else if (IVAL(pdata,0) != 4) {
1089 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1090 goto out;
1093 status = SMB_VFS_CREATE_FILE(
1094 conn, /* conn */
1095 req, /* req */
1096 0, /* root_dir_fid */
1097 smb_fname, /* fname */
1098 access_mask, /* access_mask */
1099 share_mode, /* share_access */
1100 create_disposition, /* create_disposition*/
1101 create_options, /* create_options */
1102 open_attr, /* file_attributes */
1103 oplock_request, /* oplock_request */
1104 open_size, /* allocation_size */
1105 NULL, /* sd */
1106 ea_list, /* ea_list */
1107 &fsp, /* result */
1108 &smb_action); /* psbuf */
1110 if (!NT_STATUS_IS_OK(status)) {
1111 if (open_was_deferred(req->mid)) {
1112 /* We have re-scheduled this call. */
1113 goto out;
1115 reply_openerror(req, status);
1116 goto out;
1119 size = get_file_size_stat(&smb_fname->st);
1120 fattr = dos_mode(conn, smb_fname);
1121 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1122 inode = smb_fname->st.st_ex_ino;
1123 if (fattr & aDIR) {
1124 close_file(req, fsp, ERROR_CLOSE);
1125 reply_doserror(req, ERRDOS,ERRnoaccess);
1126 goto out;
1129 /* Realloc the size of parameters and data we will return */
1130 *pparams = (char *)SMB_REALLOC(*pparams, 30);
1131 if(*pparams == NULL ) {
1132 reply_nterror(req, NT_STATUS_NO_MEMORY);
1133 goto out;
1135 params = *pparams;
1137 SSVAL(params,0,fsp->fnum);
1138 SSVAL(params,2,fattr);
1139 srv_put_dos_date2(params,4, mtime);
1140 SIVAL(params,8, (uint32)size);
1141 SSVAL(params,12,deny_mode);
1142 SSVAL(params,14,0); /* open_type - file or directory. */
1143 SSVAL(params,16,0); /* open_state - only valid for IPC device. */
1145 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1146 smb_action |= EXTENDED_OPLOCK_GRANTED;
1149 SSVAL(params,18,smb_action);
1152 * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
1154 SIVAL(params,20,inode);
1155 SSVAL(params,24,0); /* Padding. */
1156 if (flags & 8) {
1157 uint32 ea_size = estimate_ea_size(conn, fsp,
1158 fsp->fsp_name->base_name);
1159 SIVAL(params, 26, ea_size);
1160 } else {
1161 SIVAL(params, 26, 0);
1164 /* Send the required number of replies */
1165 send_trans2_replies(conn, req, params, 30, *ppdata, 0, max_data_bytes);
1166 out:
1167 TALLOC_FREE(smb_fname);
1170 /*********************************************************
1171 Routine to check if a given string matches exactly.
1172 as a special case a mask of "." does NOT match. That
1173 is required for correct wildcard semantics
1174 Case can be significant or not.
1175 **********************************************************/
1177 static bool exact_match(bool has_wild,
1178 bool case_sensitive,
1179 const char *str,
1180 const char *mask)
1182 if (mask[0] == '.' && mask[1] == 0) {
1183 return false;
1186 if (has_wild) {
1187 return false;
1190 if (case_sensitive) {
1191 return strcmp(str,mask)==0;
1192 } else {
1193 return StrCaseCmp(str,mask) == 0;
1197 /****************************************************************************
1198 Return the filetype for UNIX extensions.
1199 ****************************************************************************/
1201 static uint32 unix_filetype(mode_t mode)
1203 if(S_ISREG(mode))
1204 return UNIX_TYPE_FILE;
1205 else if(S_ISDIR(mode))
1206 return UNIX_TYPE_DIR;
1207 #ifdef S_ISLNK
1208 else if(S_ISLNK(mode))
1209 return UNIX_TYPE_SYMLINK;
1210 #endif
1211 #ifdef S_ISCHR
1212 else if(S_ISCHR(mode))
1213 return UNIX_TYPE_CHARDEV;
1214 #endif
1215 #ifdef S_ISBLK
1216 else if(S_ISBLK(mode))
1217 return UNIX_TYPE_BLKDEV;
1218 #endif
1219 #ifdef S_ISFIFO
1220 else if(S_ISFIFO(mode))
1221 return UNIX_TYPE_FIFO;
1222 #endif
1223 #ifdef S_ISSOCK
1224 else if(S_ISSOCK(mode))
1225 return UNIX_TYPE_SOCKET;
1226 #endif
1228 DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode));
1229 return UNIX_TYPE_UNKNOWN;
1232 /****************************************************************************
1233 Map wire perms onto standard UNIX permissions. Obey share restrictions.
1234 ****************************************************************************/
1236 enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_DIR};
1238 static NTSTATUS unix_perms_from_wire( connection_struct *conn,
1239 const SMB_STRUCT_STAT *psbuf,
1240 uint32 perms,
1241 enum perm_type ptype,
1242 mode_t *ret_perms)
1244 mode_t ret = 0;
1246 if (perms == SMB_MODE_NO_CHANGE) {
1247 if (!VALID_STAT(*psbuf)) {
1248 return NT_STATUS_INVALID_PARAMETER;
1249 } else {
1250 *ret_perms = psbuf->st_ex_mode;
1251 return NT_STATUS_OK;
1255 ret |= ((perms & UNIX_X_OTH ) ? S_IXOTH : 0);
1256 ret |= ((perms & UNIX_W_OTH ) ? S_IWOTH : 0);
1257 ret |= ((perms & UNIX_R_OTH ) ? S_IROTH : 0);
1258 ret |= ((perms & UNIX_X_GRP ) ? S_IXGRP : 0);
1259 ret |= ((perms & UNIX_W_GRP ) ? S_IWGRP : 0);
1260 ret |= ((perms & UNIX_R_GRP ) ? S_IRGRP : 0);
1261 ret |= ((perms & UNIX_X_USR ) ? S_IXUSR : 0);
1262 ret |= ((perms & UNIX_W_USR ) ? S_IWUSR : 0);
1263 ret |= ((perms & UNIX_R_USR ) ? S_IRUSR : 0);
1264 #ifdef S_ISVTX
1265 ret |= ((perms & UNIX_STICKY ) ? S_ISVTX : 0);
1266 #endif
1267 #ifdef S_ISGID
1268 ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0);
1269 #endif
1270 #ifdef S_ISUID
1271 ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0);
1272 #endif
1274 switch (ptype) {
1275 case PERM_NEW_FILE:
1276 /* Apply mode mask */
1277 ret &= lp_create_mask(SNUM(conn));
1278 /* Add in force bits */
1279 ret |= lp_force_create_mode(SNUM(conn));
1280 break;
1281 case PERM_NEW_DIR:
1282 ret &= lp_dir_mask(SNUM(conn));
1283 /* Add in force bits */
1284 ret |= lp_force_dir_mode(SNUM(conn));
1285 break;
1286 case PERM_EXISTING_FILE:
1287 /* Apply mode mask */
1288 ret &= lp_security_mask(SNUM(conn));
1289 /* Add in force bits */
1290 ret |= lp_force_security_mode(SNUM(conn));
1291 break;
1292 case PERM_EXISTING_DIR:
1293 /* Apply mode mask */
1294 ret &= lp_dir_security_mask(SNUM(conn));
1295 /* Add in force bits */
1296 ret |= lp_force_dir_security_mode(SNUM(conn));
1297 break;
1300 *ret_perms = ret;
1301 return NT_STATUS_OK;
1304 /****************************************************************************
1305 Needed to show the msdfs symlinks as directories. Modifies psbuf
1306 to be a directory if it's a msdfs link.
1307 ****************************************************************************/
1309 static bool check_msdfs_link(connection_struct *conn,
1310 const char *pathname,
1311 SMB_STRUCT_STAT *psbuf)
1313 int saved_errno = errno;
1314 if(lp_host_msdfs() &&
1315 lp_msdfs_root(SNUM(conn)) &&
1316 is_msdfs_link(conn, pathname, psbuf)) {
1318 DEBUG(5,("check_msdfs_link: Masquerading msdfs link %s "
1319 "as a directory\n",
1320 pathname));
1321 psbuf->st_ex_mode = (psbuf->st_ex_mode & 0xFFF) | S_IFDIR;
1322 errno = saved_errno;
1323 return true;
1325 errno = saved_errno;
1326 return false;
1330 /****************************************************************************
1331 Get a level dependent lanman2 dir entry.
1332 ****************************************************************************/
1334 struct smbd_dirptr_lanman2_state {
1335 connection_struct *conn;
1336 uint32_t info_level;
1337 bool check_mangled_names;
1338 bool has_wild;
1339 bool got_exact_match;
1342 static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx,
1343 void *private_data,
1344 const char *dname,
1345 const char *mask,
1346 char **_fname)
1348 struct smbd_dirptr_lanman2_state *state =
1349 (struct smbd_dirptr_lanman2_state *)private_data;
1350 bool ok;
1351 char mangled_name[13]; /* mangled 8.3 name. */
1352 bool got_match;
1353 const char *fname;
1355 /* Mangle fname if it's an illegal name. */
1356 if (mangle_must_mangle(dname, state->conn->params)) {
1357 ok = name_to_8_3(dname, mangled_name,
1358 true, state->conn->params);
1359 if (!ok) {
1360 return false;
1362 fname = mangled_name;
1363 } else {
1364 fname = dname;
1367 got_match = exact_match(state->has_wild,
1368 state->conn->case_sensitive,
1369 fname, mask);
1370 state->got_exact_match = got_match;
1371 if (!got_match) {
1372 got_match = mask_match(fname, mask,
1373 state->conn->case_sensitive);
1376 if(!got_match && state->check_mangled_names &&
1377 !mangle_is_8_3(fname, false, state->conn->params)) {
1379 * It turns out that NT matches wildcards against
1380 * both long *and* short names. This may explain some
1381 * of the wildcard wierdness from old DOS clients
1382 * that some people have been seeing.... JRA.
1384 /* Force the mangling into 8.3. */
1385 ok = name_to_8_3(fname, mangled_name,
1386 false, state->conn->params);
1387 if (!ok) {
1388 return false;
1391 got_match = exact_match(state->has_wild,
1392 state->conn->case_sensitive,
1393 mangled_name, mask);
1394 state->got_exact_match = got_match;
1395 if (!got_match) {
1396 got_match = mask_match(mangled_name, mask,
1397 state->conn->case_sensitive);
1401 if (!got_match) {
1402 return false;
1405 *_fname = talloc_strdup(ctx, fname);
1406 if (*_fname == NULL) {
1407 return false;
1410 return true;
1413 static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
1414 void *private_data,
1415 struct smb_filename *smb_fname,
1416 uint32_t *_mode)
1418 struct smbd_dirptr_lanman2_state *state =
1419 (struct smbd_dirptr_lanman2_state *)private_data;
1420 bool ms_dfs_link = false;
1421 uint32_t mode = 0;
1423 if (INFO_LEVEL_IS_UNIX(state->info_level)) {
1424 if (SMB_VFS_LSTAT(state->conn, smb_fname) != 0) {
1425 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1426 "Couldn't lstat [%s] (%s)\n",
1427 smb_fname_str_dbg(smb_fname),
1428 strerror(errno)));
1429 return false;
1431 } else if (!VALID_STAT(smb_fname->st) &&
1432 SMB_VFS_STAT(state->conn, smb_fname) != 0) {
1433 /* Needed to show the msdfs symlinks as
1434 * directories */
1436 ms_dfs_link = check_msdfs_link(state->conn,
1437 smb_fname->base_name,
1438 &smb_fname->st);
1439 if (!ms_dfs_link) {
1440 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1441 "Couldn't stat [%s] (%s)\n",
1442 smb_fname_str_dbg(smb_fname),
1443 strerror(errno)));
1444 return false;
1448 if (ms_dfs_link) {
1449 mode = dos_mode_msdfs(state->conn, smb_fname);
1450 } else {
1451 mode = dos_mode(state->conn, smb_fname);
1454 *_mode = mode;
1455 return true;
1458 static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
1459 connection_struct *conn,
1460 uint16_t flags2,
1461 uint32_t info_level,
1462 struct ea_list *name_list,
1463 bool check_mangled_names,
1464 bool requires_resume_key,
1465 uint32_t mode,
1466 const char *fname,
1467 const struct smb_filename *smb_fname,
1468 uint64_t space_remaining,
1469 uint8_t align,
1470 bool do_pad,
1471 char *base_data,
1472 char **ppdata,
1473 char *end_data,
1474 bool *out_of_space,
1475 uint64_t *last_entry_off)
1477 char *p, *q, *pdata = *ppdata;
1478 uint32_t reskey=0;
1479 uint64_t file_size = 0;
1480 uint64_t allocation_size = 0;
1481 uint32_t len;
1482 struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts;
1483 time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
1484 time_t c_date = (time_t)0;
1485 char *nameptr;
1486 char *last_entry_ptr;
1487 bool was_8_3;
1488 uint32_t nt_extmode; /* Used for NT connections instead of mode */
1489 off_t off;
1490 off_t pad = 0;
1492 *out_of_space = false;
1494 ZERO_STRUCT(mdate_ts);
1495 ZERO_STRUCT(adate_ts);
1496 ZERO_STRUCT(create_date_ts);
1497 ZERO_STRUCT(cdate_ts);
1499 if (!(mode & aDIR)) {
1500 file_size = get_file_size_stat(&smb_fname->st);
1502 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
1504 mdate_ts = smb_fname->st.st_ex_mtime;
1505 adate_ts = smb_fname->st.st_ex_atime;
1506 create_date_ts = get_create_timespec(conn, NULL, smb_fname);
1507 cdate_ts = get_change_timespec(conn, NULL, smb_fname);
1509 if (lp_dos_filetime_resolution(SNUM(conn))) {
1510 dos_filetime_timespec(&create_date_ts);
1511 dos_filetime_timespec(&mdate_ts);
1512 dos_filetime_timespec(&adate_ts);
1513 dos_filetime_timespec(&cdate_ts);
1516 create_date = convert_timespec_to_time_t(create_date_ts);
1517 mdate = convert_timespec_to_time_t(mdate_ts);
1518 adate = convert_timespec_to_time_t(adate_ts);
1519 c_date = convert_timespec_to_time_t(cdate_ts);
1521 /* align the record */
1522 off = PTR_DIFF(pdata, base_data);
1523 pad = (off + (align-1)) & ~(align-1);
1524 pad -= off;
1525 off += pad;
1526 /* initialize padding to 0 */
1527 memset(pdata, 0, pad);
1528 space_remaining -= pad;
1530 pdata += pad;
1531 p = pdata;
1532 last_entry_ptr = p;
1534 pad = 0;
1535 off = 0;
1537 nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
1539 switch (info_level) {
1540 case SMB_FIND_INFO_STANDARD:
1541 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_INFO_STANDARD\n"));
1542 if(requires_resume_key) {
1543 SIVAL(p,0,reskey);
1544 p += 4;
1546 srv_put_dos_date2(p,0,create_date);
1547 srv_put_dos_date2(p,4,adate);
1548 srv_put_dos_date2(p,8,mdate);
1549 SIVAL(p,12,(uint32)file_size);
1550 SIVAL(p,16,(uint32)allocation_size);
1551 SSVAL(p,20,mode);
1552 p += 23;
1553 nameptr = p;
1554 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1555 p += ucs2_align(base_data, p, 0);
1557 len = srvstr_push(base_data, flags2, p,
1558 fname, PTR_DIFF(end_data, p),
1559 STR_TERMINATE);
1560 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1561 if (len > 2) {
1562 SCVAL(nameptr, -1, len - 2);
1563 } else {
1564 SCVAL(nameptr, -1, 0);
1566 } else {
1567 if (len > 1) {
1568 SCVAL(nameptr, -1, len - 1);
1569 } else {
1570 SCVAL(nameptr, -1, 0);
1573 p += len;
1574 break;
1576 case SMB_FIND_EA_SIZE:
1577 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_SIZE\n"));
1578 if (requires_resume_key) {
1579 SIVAL(p,0,reskey);
1580 p += 4;
1582 srv_put_dos_date2(p,0,create_date);
1583 srv_put_dos_date2(p,4,adate);
1584 srv_put_dos_date2(p,8,mdate);
1585 SIVAL(p,12,(uint32)file_size);
1586 SIVAL(p,16,(uint32)allocation_size);
1587 SSVAL(p,20,mode);
1589 unsigned int ea_size = estimate_ea_size(conn, NULL,
1590 smb_fname->base_name);
1591 SIVAL(p,22,ea_size); /* Extended attributes */
1593 p += 27;
1594 nameptr = p - 1;
1595 len = srvstr_push(base_data, flags2,
1596 p, fname, PTR_DIFF(end_data, p),
1597 STR_TERMINATE | STR_NOALIGN);
1598 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1599 if (len > 2) {
1600 len -= 2;
1601 } else {
1602 len = 0;
1604 } else {
1605 if (len > 1) {
1606 len -= 1;
1607 } else {
1608 len = 0;
1611 SCVAL(nameptr,0,len);
1612 p += len;
1613 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1614 break;
1616 case SMB_FIND_EA_LIST:
1618 struct ea_list *file_list = NULL;
1619 size_t ea_len = 0;
1621 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_LIST\n"));
1622 if (!name_list) {
1623 return false;
1625 if (requires_resume_key) {
1626 SIVAL(p,0,reskey);
1627 p += 4;
1629 srv_put_dos_date2(p,0,create_date);
1630 srv_put_dos_date2(p,4,adate);
1631 srv_put_dos_date2(p,8,mdate);
1632 SIVAL(p,12,(uint32)file_size);
1633 SIVAL(p,16,(uint32)allocation_size);
1634 SSVAL(p,20,mode);
1635 p += 22; /* p now points to the EA area. */
1637 file_list = get_ea_list_from_file(ctx, conn, NULL,
1638 smb_fname->base_name,
1639 &ea_len);
1640 name_list = ea_list_union(name_list, file_list, &ea_len);
1642 /* We need to determine if this entry will fit in the space available. */
1643 /* Max string size is 255 bytes. */
1644 if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
1645 *out_of_space = true;
1646 DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
1647 return False; /* Not finished - just out of space */
1650 /* Push the ea_data followed by the name. */
1651 p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
1652 nameptr = p;
1653 len = srvstr_push(base_data, flags2,
1654 p + 1, fname, PTR_DIFF(end_data, p+1),
1655 STR_TERMINATE | STR_NOALIGN);
1656 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1657 if (len > 2) {
1658 len -= 2;
1659 } else {
1660 len = 0;
1662 } else {
1663 if (len > 1) {
1664 len -= 1;
1665 } else {
1666 len = 0;
1669 SCVAL(nameptr,0,len);
1670 p += len + 1;
1671 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1672 break;
1675 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
1676 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
1677 was_8_3 = mangle_is_8_3(fname, True, conn->params);
1678 p += 4;
1679 SIVAL(p,0,reskey); p += 4;
1680 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1681 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1682 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1683 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1684 SOFF_T(p,0,file_size); p += 8;
1685 SOFF_T(p,0,allocation_size); p += 8;
1686 SIVAL(p,0,nt_extmode); p += 4;
1687 q = p; p += 4; /* q is placeholder for name length. */
1689 unsigned int ea_size = estimate_ea_size(conn, NULL,
1690 smb_fname->base_name);
1691 SIVAL(p,0,ea_size); /* Extended attributes */
1692 p += 4;
1694 /* Clear the short name buffer. This is
1695 * IMPORTANT as not doing so will trigger
1696 * a Win2k client bug. JRA.
1698 if (!was_8_3 && check_mangled_names) {
1699 char mangled_name[13]; /* mangled 8.3 name. */
1700 if (!name_to_8_3(fname,mangled_name,True,
1701 conn->params)) {
1702 /* Error - mangle failed ! */
1703 memset(mangled_name,'\0',12);
1705 mangled_name[12] = 0;
1706 len = srvstr_push(base_data, flags2,
1707 p+2, mangled_name, 24,
1708 STR_UPPER|STR_UNICODE);
1709 if (len < 24) {
1710 memset(p + 2 + len,'\0',24 - len);
1712 SSVAL(p, 0, len);
1713 } else {
1714 memset(p,'\0',26);
1716 p += 2 + 24;
1717 len = srvstr_push(base_data, flags2, p,
1718 fname, PTR_DIFF(end_data, p),
1719 STR_TERMINATE_ASCII);
1720 SIVAL(q,0,len);
1721 p += len;
1723 len = PTR_DIFF(p, pdata);
1724 pad = (len + (align-1)) & ~(align-1);
1726 * offset to the next entry, the caller
1727 * will overwrite it for the last entry
1728 * that's why we always include the padding
1730 SIVAL(pdata,0,pad);
1732 * set padding to zero
1734 if (do_pad) {
1735 memset(p, 0, pad - len);
1736 p = pdata + pad;
1737 } else {
1738 p = pdata + len;
1740 break;
1742 case SMB_FIND_FILE_DIRECTORY_INFO:
1743 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
1744 p += 4;
1745 SIVAL(p,0,reskey); p += 4;
1746 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1747 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1748 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1749 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1750 SOFF_T(p,0,file_size); p += 8;
1751 SOFF_T(p,0,allocation_size); p += 8;
1752 SIVAL(p,0,nt_extmode); p += 4;
1753 len = srvstr_push(base_data, flags2,
1754 p + 4, fname, PTR_DIFF(end_data, p+4),
1755 STR_TERMINATE_ASCII);
1756 SIVAL(p,0,len);
1757 p += 4 + len;
1759 len = PTR_DIFF(p, pdata);
1760 pad = (len + (align-1)) & ~(align-1);
1762 * offset to the next entry, the caller
1763 * will overwrite it for the last entry
1764 * that's why we always include the padding
1766 SIVAL(pdata,0,pad);
1768 * set padding to zero
1770 if (do_pad) {
1771 memset(p, 0, pad - len);
1772 p = pdata + pad;
1773 } else {
1774 p = pdata + len;
1776 break;
1778 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
1779 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
1780 p += 4;
1781 SIVAL(p,0,reskey); p += 4;
1782 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1783 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1784 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1785 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1786 SOFF_T(p,0,file_size); p += 8;
1787 SOFF_T(p,0,allocation_size); p += 8;
1788 SIVAL(p,0,nt_extmode); p += 4;
1789 q = p; p += 4; /* q is placeholder for name length. */
1791 unsigned int ea_size = estimate_ea_size(conn, NULL,
1792 smb_fname->base_name);
1793 SIVAL(p,0,ea_size); /* Extended attributes */
1794 p +=4;
1796 len = srvstr_push(base_data, flags2, p,
1797 fname, PTR_DIFF(end_data, p),
1798 STR_TERMINATE_ASCII);
1799 SIVAL(q, 0, len);
1800 p += len;
1802 len = PTR_DIFF(p, pdata);
1803 pad = (len + (align-1)) & ~(align-1);
1805 * offset to the next entry, the caller
1806 * will overwrite it for the last entry
1807 * that's why we always include the padding
1809 SIVAL(pdata,0,pad);
1811 * set padding to zero
1813 if (do_pad) {
1814 memset(p, 0, pad - len);
1815 p = pdata + pad;
1816 } else {
1817 p = pdata + len;
1819 break;
1821 case SMB_FIND_FILE_NAMES_INFO:
1822 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
1823 p += 4;
1824 SIVAL(p,0,reskey); p += 4;
1825 p += 4;
1826 /* this must *not* be null terminated or w2k gets in a loop trying to set an
1827 acl on a dir (tridge) */
1828 len = srvstr_push(base_data, flags2, p,
1829 fname, PTR_DIFF(end_data, p),
1830 STR_TERMINATE_ASCII);
1831 SIVAL(p, -4, len);
1832 p += len;
1834 len = PTR_DIFF(p, pdata);
1835 pad = (len + (align-1)) & ~(align-1);
1837 * offset to the next entry, the caller
1838 * will overwrite it for the last entry
1839 * that's why we always include the padding
1841 SIVAL(pdata,0,pad);
1843 * set padding to zero
1845 if (do_pad) {
1846 memset(p, 0, pad - len);
1847 p = pdata + pad;
1848 } else {
1849 p = pdata + len;
1851 break;
1853 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
1854 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
1855 p += 4;
1856 SIVAL(p,0,reskey); p += 4;
1857 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1858 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1859 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1860 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1861 SOFF_T(p,0,file_size); p += 8;
1862 SOFF_T(p,0,allocation_size); p += 8;
1863 SIVAL(p,0,nt_extmode); p += 4;
1864 q = p; p += 4; /* q is placeholder for name length. */
1866 unsigned int ea_size = estimate_ea_size(conn, NULL,
1867 smb_fname->base_name);
1868 SIVAL(p,0,ea_size); /* Extended attributes */
1869 p +=4;
1871 SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
1872 SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
1873 SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
1874 len = srvstr_push(base_data, flags2, p,
1875 fname, PTR_DIFF(end_data, p),
1876 STR_TERMINATE_ASCII);
1877 SIVAL(q, 0, len);
1878 p += len;
1880 len = PTR_DIFF(p, pdata);
1881 pad = (len + (align-1)) & ~(align-1);
1883 * offset to the next entry, the caller
1884 * will overwrite it for the last entry
1885 * that's why we always include the padding
1887 SIVAL(pdata,0,pad);
1889 * set padding to zero
1891 if (do_pad) {
1892 memset(p, 0, pad - len);
1893 p = pdata + pad;
1894 } else {
1895 p = pdata + len;
1897 break;
1899 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
1900 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
1901 was_8_3 = mangle_is_8_3(fname, True, conn->params);
1902 p += 4;
1903 SIVAL(p,0,reskey); p += 4;
1904 put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
1905 put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
1906 put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
1907 put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
1908 SOFF_T(p,0,file_size); p += 8;
1909 SOFF_T(p,0,allocation_size); p += 8;
1910 SIVAL(p,0,nt_extmode); p += 4;
1911 q = p; p += 4; /* q is placeholder for name length */
1913 unsigned int ea_size = estimate_ea_size(conn, NULL,
1914 smb_fname->base_name);
1915 SIVAL(p,0,ea_size); /* Extended attributes */
1916 p +=4;
1918 /* Clear the short name buffer. This is
1919 * IMPORTANT as not doing so will trigger
1920 * a Win2k client bug. JRA.
1922 if (!was_8_3 && check_mangled_names) {
1923 char mangled_name[13]; /* mangled 8.3 name. */
1924 if (!name_to_8_3(fname,mangled_name,True,
1925 conn->params)) {
1926 /* Error - mangle failed ! */
1927 memset(mangled_name,'\0',12);
1929 mangled_name[12] = 0;
1930 len = srvstr_push(base_data, flags2,
1931 p+2, mangled_name, 24,
1932 STR_UPPER|STR_UNICODE);
1933 SSVAL(p, 0, len);
1934 if (len < 24) {
1935 memset(p + 2 + len,'\0',24 - len);
1937 SSVAL(p, 0, len);
1938 } else {
1939 memset(p,'\0',26);
1941 p += 26;
1942 SSVAL(p,0,0); p += 2; /* Reserved ? */
1943 SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
1944 SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
1945 len = srvstr_push(base_data, flags2, p,
1946 fname, PTR_DIFF(end_data, p),
1947 STR_TERMINATE_ASCII);
1948 SIVAL(q,0,len);
1949 p += len;
1951 len = PTR_DIFF(p, pdata);
1952 pad = (len + (align-1)) & ~(align-1);
1954 * offset to the next entry, the caller
1955 * will overwrite it for the last entry
1956 * that's why we always include the padding
1958 SIVAL(pdata,0,pad);
1960 * set padding to zero
1962 if (do_pad) {
1963 memset(p, 0, pad - len);
1964 p = pdata + pad;
1965 } else {
1966 p = pdata + len;
1968 break;
1970 /* CIFS UNIX Extension. */
1972 case SMB_FIND_FILE_UNIX:
1973 case SMB_FIND_FILE_UNIX_INFO2:
1974 p+= 4;
1975 SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
1977 /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
1979 if (info_level == SMB_FIND_FILE_UNIX) {
1980 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
1981 p = store_file_unix_basic(conn, p,
1982 NULL, &smb_fname->st);
1983 len = srvstr_push(base_data, flags2, p,
1984 fname, PTR_DIFF(end_data, p),
1985 STR_TERMINATE);
1986 } else {
1987 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
1988 p = store_file_unix_basic_info2(conn, p,
1989 NULL, &smb_fname->st);
1990 nameptr = p;
1991 p += 4;
1992 len = srvstr_push(base_data, flags2, p, fname,
1993 PTR_DIFF(end_data, p), 0);
1994 SIVAL(nameptr, 0, len);
1997 p += len;
1999 len = PTR_DIFF(p, pdata);
2000 pad = (len + (align-1)) & ~(align-1);
2002 * offset to the next entry, the caller
2003 * will overwrite it for the last entry
2004 * that's why we always include the padding
2006 SIVAL(pdata,0,pad);
2008 * set padding to zero
2010 if (do_pad) {
2011 memset(p, 0, pad - len);
2012 p = pdata + pad;
2013 } else {
2014 p = pdata + len;
2016 /* End of SMB_QUERY_FILE_UNIX_BASIC */
2018 break;
2020 default:
2021 return false;
2024 if (PTR_DIFF(p,pdata) > space_remaining) {
2025 *out_of_space = true;
2026 DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
2027 return false; /* Not finished - just out of space */
2030 /* Setup the last entry pointer, as an offset from base_data */
2031 *last_entry_off = PTR_DIFF(last_entry_ptr,base_data);
2032 /* Advance the data pointer to the next slot */
2033 *ppdata = p;
2035 return true;
2038 bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
2039 connection_struct *conn,
2040 struct dptr_struct *dirptr,
2041 uint16 flags2,
2042 const char *path_mask,
2043 uint32 dirtype,
2044 int info_level,
2045 int requires_resume_key,
2046 bool dont_descend,
2047 bool ask_sharemode,
2048 uint8_t align,
2049 bool do_pad,
2050 char **ppdata,
2051 char *base_data,
2052 char *end_data,
2053 int space_remaining,
2054 bool *out_of_space,
2055 bool *got_exact_match,
2056 int *_last_entry_off,
2057 struct ea_list *name_list)
2059 const char *p;
2060 const char *mask = NULL;
2061 long prev_dirpos = 0;
2062 uint32_t mode = 0;
2063 char *fname = NULL;
2064 struct smb_filename *smb_fname = NULL;
2065 struct smbd_dirptr_lanman2_state state;
2066 bool ok;
2067 uint64_t last_entry_off = 0;
2069 ZERO_STRUCT(state);
2070 state.conn = conn;
2071 state.info_level = info_level;
2072 state.check_mangled_names = lp_manglednames(conn->params);
2073 state.has_wild = dptr_has_wild(dirptr);
2074 state.got_exact_match = false;
2076 *out_of_space = false;
2077 *got_exact_match = false;
2079 p = strrchr_m(path_mask,'/');
2080 if(p != NULL) {
2081 if(p[1] == '\0') {
2082 mask = "*.*";
2083 } else {
2084 mask = p+1;
2086 } else {
2087 mask = path_mask;
2090 ok = smbd_dirptr_get_entry(ctx,
2091 dirptr,
2092 mask,
2093 dirtype,
2094 dont_descend,
2095 ask_sharemode,
2096 smbd_dirptr_lanman2_match_fn,
2097 smbd_dirptr_lanman2_mode_fn,
2098 &state,
2099 &fname,
2100 &smb_fname,
2101 &mode,
2102 &prev_dirpos);
2103 if (!ok) {
2104 return false;
2107 *got_exact_match = state.got_exact_match;
2109 ok = smbd_marshall_dir_entry(ctx,
2110 conn,
2111 flags2,
2112 info_level,
2113 name_list,
2114 state.check_mangled_names,
2115 requires_resume_key,
2116 mode,
2117 fname,
2118 smb_fname,
2119 space_remaining,
2120 align,
2121 do_pad,
2122 base_data,
2123 ppdata,
2124 end_data,
2125 out_of_space,
2126 &last_entry_off);
2127 TALLOC_FREE(fname);
2128 TALLOC_FREE(smb_fname);
2129 if (*out_of_space) {
2130 dptr_SeekDir(dirptr, prev_dirpos);
2131 return false;
2133 if (!ok) {
2134 return false;
2137 *_last_entry_off = last_entry_off;
2138 return true;
2141 static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
2142 connection_struct *conn,
2143 struct dptr_struct *dirptr,
2144 uint16 flags2,
2145 const char *path_mask,
2146 uint32 dirtype,
2147 int info_level,
2148 int requires_resume_key,
2149 bool dont_descend,
2150 bool ask_sharemode,
2151 char **ppdata,
2152 char *base_data,
2153 char *end_data,
2154 int space_remaining,
2155 bool *out_of_space,
2156 bool *got_exact_match,
2157 int *last_entry_off,
2158 struct ea_list *name_list)
2160 bool resume_key = false;
2161 const uint8_t align = 4;
2162 const bool do_pad = true;
2164 if (requires_resume_key) {
2165 resume_key = true;
2168 return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2,
2169 path_mask, dirtype, info_level,
2170 resume_key, dont_descend, ask_sharemode,
2171 align, do_pad,
2172 ppdata, base_data, end_data,
2173 space_remaining,
2174 out_of_space, got_exact_match,
2175 last_entry_off, name_list);
2178 /****************************************************************************
2179 Reply to a TRANS2_FINDFIRST.
2180 ****************************************************************************/
2182 static void call_trans2findfirst(connection_struct *conn,
2183 struct smb_request *req,
2184 char **pparams, int total_params,
2185 char **ppdata, int total_data,
2186 unsigned int max_data_bytes)
2188 /* We must be careful here that we don't return more than the
2189 allowed number of data bytes. If this means returning fewer than
2190 maxentries then so be it. We assume that the redirector has
2191 enough room for the fixed number of parameter bytes it has
2192 requested. */
2193 struct smb_filename *smb_dname = NULL;
2194 char *params = *pparams;
2195 char *pdata = *ppdata;
2196 char *data_end;
2197 uint32 dirtype;
2198 int maxentries;
2199 uint16 findfirst_flags;
2200 bool close_after_first;
2201 bool close_if_end;
2202 bool requires_resume_key;
2203 int info_level;
2204 char *directory = NULL;
2205 char *mask = NULL;
2206 char *p;
2207 int last_entry_off=0;
2208 int dptr_num = -1;
2209 int numentries = 0;
2210 int i;
2211 bool finished = False;
2212 bool dont_descend = False;
2213 bool out_of_space = False;
2214 int space_remaining;
2215 bool mask_contains_wcard = False;
2216 struct ea_list *ea_list = NULL;
2217 NTSTATUS ntstatus = NT_STATUS_OK;
2218 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
2219 TALLOC_CTX *ctx = talloc_tos();
2220 struct dptr_struct *dirptr = NULL;
2221 struct smbd_server_connection *sconn = smbd_server_conn;
2223 if (total_params < 13) {
2224 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2225 goto out;
2228 dirtype = SVAL(params,0);
2229 maxentries = SVAL(params,2);
2230 findfirst_flags = SVAL(params,4);
2231 close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
2232 close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
2233 requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
2234 info_level = SVAL(params,6);
2236 DEBUG(3,("call_trans2findfirst: dirtype = %x, maxentries = %d, close_after_first=%d, \
2237 close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
2238 (unsigned int)dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
2239 info_level, max_data_bytes));
2241 if (!maxentries) {
2242 /* W2K3 seems to treat zero as 1. */
2243 maxentries = 1;
2246 switch (info_level) {
2247 case SMB_FIND_INFO_STANDARD:
2248 case SMB_FIND_EA_SIZE:
2249 case SMB_FIND_EA_LIST:
2250 case SMB_FIND_FILE_DIRECTORY_INFO:
2251 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
2252 case SMB_FIND_FILE_NAMES_INFO:
2253 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
2254 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
2255 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
2256 break;
2257 case SMB_FIND_FILE_UNIX:
2258 case SMB_FIND_FILE_UNIX_INFO2:
2259 /* Always use filesystem for UNIX mtime query. */
2260 ask_sharemode = false;
2261 if (!lp_unix_extensions()) {
2262 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2263 goto out;
2265 break;
2266 default:
2267 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2268 goto out;
2271 srvstr_get_path_wcard(ctx, params, req->flags2, &directory,
2272 params+12, total_params - 12,
2273 STR_TERMINATE, &ntstatus, &mask_contains_wcard);
2274 if (!NT_STATUS_IS_OK(ntstatus)) {
2275 reply_nterror(req, ntstatus);
2276 goto out;
2279 ntstatus = filename_convert(ctx, conn,
2280 req->flags2 & FLAGS2_DFS_PATHNAMES,
2281 directory,
2282 (UCF_SAVE_LCOMP |
2283 UCF_ALWAYS_ALLOW_WCARD_LCOMP),
2284 &mask_contains_wcard,
2285 &smb_dname);
2286 if (!NT_STATUS_IS_OK(ntstatus)) {
2287 if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
2288 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2289 ERRSRV, ERRbadpath);
2290 goto out;
2292 reply_nterror(req, ntstatus);
2293 goto out;
2296 mask = smb_dname->original_lcomp;
2298 directory = smb_dname->base_name;
2300 p = strrchr_m(directory,'/');
2301 if(p == NULL) {
2302 /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */
2303 if((directory[0] == '.') && (directory[1] == '\0')) {
2304 mask = talloc_strdup(ctx,"*");
2305 if (!mask) {
2306 reply_nterror(req, NT_STATUS_NO_MEMORY);
2307 goto out;
2309 mask_contains_wcard = True;
2311 directory = talloc_strdup(talloc_tos(), "./");
2312 if (!directory) {
2313 reply_nterror(req, NT_STATUS_NO_MEMORY);
2314 goto out;
2316 } else {
2317 *p = 0;
2320 DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
2322 if (info_level == SMB_FIND_EA_LIST) {
2323 uint32 ea_size;
2325 if (total_data < 4) {
2326 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2327 goto out;
2330 ea_size = IVAL(pdata,0);
2331 if (ea_size != total_data) {
2332 DEBUG(4,("call_trans2findfirst: Rejecting EA request with incorrect \
2333 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2334 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2335 goto out;
2338 if (!lp_ea_support(SNUM(conn))) {
2339 reply_doserror(req, ERRDOS, ERReasnotsupported);
2340 goto out;
2343 /* Pull out the list of names. */
2344 ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
2345 if (!ea_list) {
2346 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2347 goto out;
2351 *ppdata = (char *)SMB_REALLOC(
2352 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2353 if(*ppdata == NULL ) {
2354 reply_nterror(req, NT_STATUS_NO_MEMORY);
2355 goto out;
2357 pdata = *ppdata;
2358 data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2360 /* Realloc the params space */
2361 *pparams = (char *)SMB_REALLOC(*pparams, 10);
2362 if (*pparams == NULL) {
2363 reply_nterror(req, NT_STATUS_NO_MEMORY);
2364 goto out;
2366 params = *pparams;
2368 /* Save the wildcard match and attribs we are using on this directory -
2369 needed as lanman2 assumes these are being saved between calls */
2371 ntstatus = dptr_create(conn,
2372 directory,
2373 False,
2374 True,
2375 req->smbpid,
2376 mask,
2377 mask_contains_wcard,
2378 dirtype,
2379 &dirptr);
2381 if (!NT_STATUS_IS_OK(ntstatus)) {
2382 reply_nterror(req, ntstatus);
2383 goto out;
2386 dptr_num = dptr_dnum(dirptr);
2387 DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));
2389 /* Initialize per TRANS2_FIND_FIRST operation data */
2390 dptr_init_search_op(dirptr);
2392 /* We don't need to check for VOL here as this is returned by
2393 a different TRANS2 call. */
2395 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
2396 directory,lp_dontdescend(SNUM(conn))));
2397 if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
2398 dont_descend = True;
2400 p = pdata;
2401 space_remaining = max_data_bytes;
2402 out_of_space = False;
2404 for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
2405 bool got_exact_match = False;
2407 /* this is a heuristic to avoid seeking the dirptr except when
2408 absolutely necessary. It allows for a filename of about 40 chars */
2409 if (space_remaining < DIRLEN_GUESS && numentries > 0) {
2410 out_of_space = True;
2411 finished = False;
2412 } else {
2413 finished = !get_lanman2_dir_entry(ctx,
2414 conn,
2415 dirptr,
2416 req->flags2,
2417 mask,dirtype,info_level,
2418 requires_resume_key,dont_descend,
2419 ask_sharemode,
2420 &p,pdata,data_end,
2421 space_remaining, &out_of_space,
2422 &got_exact_match,
2423 &last_entry_off, ea_list);
2426 if (finished && out_of_space)
2427 finished = False;
2429 if (!finished && !out_of_space)
2430 numentries++;
2433 * As an optimisation if we know we aren't looking
2434 * for a wildcard name (ie. the name matches the wildcard exactly)
2435 * then we can finish on any (first) match.
2436 * This speeds up large directory searches. JRA.
2439 if(got_exact_match)
2440 finished = True;
2442 /* Ensure space_remaining never goes -ve. */
2443 if (PTR_DIFF(p,pdata) > max_data_bytes) {
2444 space_remaining = 0;
2445 out_of_space = true;
2446 } else {
2447 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
2451 /* Check if we can close the dirptr */
2452 if(close_after_first || (finished && close_if_end)) {
2453 DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
2454 dptr_close(sconn, &dptr_num);
2458 * If there are no matching entries we must return ERRDOS/ERRbadfile -
2459 * from observation of NT. NB. This changes to ERRDOS,ERRnofiles if
2460 * the protocol level is less than NT1. Tested with smbclient. JRA.
2461 * This should fix the OS/2 client bug #2335.
2464 if(numentries == 0) {
2465 dptr_close(sconn, &dptr_num);
2466 if (Protocol < PROTOCOL_NT1) {
2467 reply_doserror(req, ERRDOS, ERRnofiles);
2468 goto out;
2469 } else {
2470 reply_botherror(req, NT_STATUS_NO_SUCH_FILE,
2471 ERRDOS, ERRbadfile);
2472 goto out;
2476 /* At this point pdata points to numentries directory entries. */
2478 /* Set up the return parameter block */
2479 SSVAL(params,0,dptr_num);
2480 SSVAL(params,2,numentries);
2481 SSVAL(params,4,finished);
2482 SSVAL(params,6,0); /* Never an EA error */
2483 SSVAL(params,8,last_entry_off);
2485 send_trans2_replies(conn, req, params, 10, pdata, PTR_DIFF(p,pdata),
2486 max_data_bytes);
2488 if ((! *directory) && dptr_path(sconn, dptr_num)) {
2489 directory = talloc_strdup(talloc_tos(),dptr_path(sconn, dptr_num));
2490 if (!directory) {
2491 reply_nterror(req, NT_STATUS_NO_MEMORY);
2495 DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
2496 smb_fn_name(req->cmd),
2497 mask, directory, dirtype, numentries ) );
2500 * Force a name mangle here to ensure that the
2501 * mask as an 8.3 name is top of the mangled cache.
2502 * The reasons for this are subtle. Don't remove
2503 * this code unless you know what you are doing
2504 * (see PR#13758). JRA.
2507 if(!mangle_is_8_3_wildcards( mask, False, conn->params)) {
2508 char mangled_name[13];
2509 name_to_8_3(mask, mangled_name, True, conn->params);
2511 out:
2512 TALLOC_FREE(smb_dname);
2513 return;
2516 /****************************************************************************
2517 Reply to a TRANS2_FINDNEXT.
2518 ****************************************************************************/
2520 static void call_trans2findnext(connection_struct *conn,
2521 struct smb_request *req,
2522 char **pparams, int total_params,
2523 char **ppdata, int total_data,
2524 unsigned int max_data_bytes)
2526 /* We must be careful here that we don't return more than the
2527 allowed number of data bytes. If this means returning fewer than
2528 maxentries then so be it. We assume that the redirector has
2529 enough room for the fixed number of parameter bytes it has
2530 requested. */
2531 char *params = *pparams;
2532 char *pdata = *ppdata;
2533 char *data_end;
2534 int dptr_num;
2535 int maxentries;
2536 uint16 info_level;
2537 uint32 resume_key;
2538 uint16 findnext_flags;
2539 bool close_after_request;
2540 bool close_if_end;
2541 bool requires_resume_key;
2542 bool continue_bit;
2543 bool mask_contains_wcard = False;
2544 char *resume_name = NULL;
2545 const char *mask = NULL;
2546 const char *directory = NULL;
2547 char *p = NULL;
2548 uint16 dirtype;
2549 int numentries = 0;
2550 int i, last_entry_off=0;
2551 bool finished = False;
2552 bool dont_descend = False;
2553 bool out_of_space = False;
2554 int space_remaining;
2555 struct ea_list *ea_list = NULL;
2556 NTSTATUS ntstatus = NT_STATUS_OK;
2557 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
2558 TALLOC_CTX *ctx = talloc_tos();
2559 struct dptr_struct *dirptr;
2560 struct smbd_server_connection *sconn = smbd_server_conn;
2562 if (total_params < 13) {
2563 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2564 return;
2567 dptr_num = SVAL(params,0);
2568 maxentries = SVAL(params,2);
2569 info_level = SVAL(params,4);
2570 resume_key = IVAL(params,6);
2571 findnext_flags = SVAL(params,10);
2572 close_after_request = (findnext_flags & FLAG_TRANS2_FIND_CLOSE);
2573 close_if_end = (findnext_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
2574 requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
2575 continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE);
2577 srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name,
2578 params+12,
2579 total_params - 12, STR_TERMINATE, &ntstatus,
2580 &mask_contains_wcard);
2581 if (!NT_STATUS_IS_OK(ntstatus)) {
2582 /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
2583 complain (it thinks we're asking for the directory above the shared
2584 path or an invalid name). Catch this as the resume name is only compared, never used in
2585 a file access. JRA. */
2586 srvstr_pull_talloc(ctx, params, req->flags2,
2587 &resume_name, params+12,
2588 total_params - 12,
2589 STR_TERMINATE);
2591 if (!resume_name || !(ISDOT(resume_name) || ISDOTDOT(resume_name))) {
2592 reply_nterror(req, ntstatus);
2593 return;
2597 DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \
2598 close_after_request=%d, close_if_end = %d requires_resume_key = %d \
2599 resume_key = %d resume name = %s continue=%d level = %d\n",
2600 dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end,
2601 requires_resume_key, resume_key, resume_name, continue_bit, info_level));
2603 if (!maxentries) {
2604 /* W2K3 seems to treat zero as 1. */
2605 maxentries = 1;
2608 switch (info_level) {
2609 case SMB_FIND_INFO_STANDARD:
2610 case SMB_FIND_EA_SIZE:
2611 case SMB_FIND_EA_LIST:
2612 case SMB_FIND_FILE_DIRECTORY_INFO:
2613 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
2614 case SMB_FIND_FILE_NAMES_INFO:
2615 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
2616 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
2617 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
2618 break;
2619 case SMB_FIND_FILE_UNIX:
2620 case SMB_FIND_FILE_UNIX_INFO2:
2621 /* Always use filesystem for UNIX mtime query. */
2622 ask_sharemode = false;
2623 if (!lp_unix_extensions()) {
2624 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2625 return;
2627 break;
2628 default:
2629 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2630 return;
2633 if (info_level == SMB_FIND_EA_LIST) {
2634 uint32 ea_size;
2636 if (total_data < 4) {
2637 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2638 return;
2641 ea_size = IVAL(pdata,0);
2642 if (ea_size != total_data) {
2643 DEBUG(4,("call_trans2findnext: Rejecting EA request with incorrect \
2644 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2645 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2646 return;
2649 if (!lp_ea_support(SNUM(conn))) {
2650 reply_doserror(req, ERRDOS, ERReasnotsupported);
2651 return;
2654 /* Pull out the list of names. */
2655 ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
2656 if (!ea_list) {
2657 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2658 return;
2662 *ppdata = (char *)SMB_REALLOC(
2663 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2664 if(*ppdata == NULL) {
2665 reply_nterror(req, NT_STATUS_NO_MEMORY);
2666 return;
2669 pdata = *ppdata;
2670 data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2672 /* Realloc the params space */
2673 *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD);
2674 if(*pparams == NULL ) {
2675 reply_nterror(req, NT_STATUS_NO_MEMORY);
2676 return;
2679 params = *pparams;
2681 /* Check that the dptr is valid */
2682 if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) {
2683 reply_doserror(req, ERRDOS, ERRnofiles);
2684 return;
2687 directory = dptr_path(sconn, dptr_num);
2689 /* Get the wildcard mask from the dptr */
2690 if((p = dptr_wcard(sconn, dptr_num))== NULL) {
2691 DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
2692 reply_doserror(req, ERRDOS, ERRnofiles);
2693 return;
2696 mask = p;
2698 /* Get the attr mask from the dptr */
2699 dirtype = dptr_attr(sconn, dptr_num);
2701 DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld)\n",
2702 dptr_num, mask, dirtype,
2703 (long)dirptr,
2704 dptr_TellDir(dirptr)));
2706 /* Initialize per TRANS2_FIND_NEXT operation data */
2707 dptr_init_search_op(dirptr);
2709 /* We don't need to check for VOL here as this is returned by
2710 a different TRANS2 call. */
2712 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
2713 directory,lp_dontdescend(SNUM(conn))));
2714 if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
2715 dont_descend = True;
2717 p = pdata;
2718 space_remaining = max_data_bytes;
2719 out_of_space = False;
2722 * Seek to the correct position. We no longer use the resume key but
2723 * depend on the last file name instead.
2726 if(*resume_name && !continue_bit) {
2727 SMB_STRUCT_STAT st;
2729 long current_pos = 0;
2731 * Remember, name_to_8_3 is called by
2732 * get_lanman2_dir_entry(), so the resume name
2733 * could be mangled. Ensure we check the unmangled name.
2736 if (mangle_is_mangled(resume_name, conn->params)) {
2737 char *new_resume_name = NULL;
2738 mangle_lookup_name_from_8_3(ctx,
2739 resume_name,
2740 &new_resume_name,
2741 conn->params);
2742 if (new_resume_name) {
2743 resume_name = new_resume_name;
2748 * Fix for NT redirector problem triggered by resume key indexes
2749 * changing between directory scans. We now return a resume key of 0
2750 * and instead look for the filename to continue from (also given
2751 * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
2752 * findfirst/findnext (as is usual) then the directory pointer
2753 * should already be at the correct place.
2756 finished = !dptr_SearchDir(dirptr, resume_name, &current_pos, &st);
2757 } /* end if resume_name && !continue_bit */
2759 for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
2760 bool got_exact_match = False;
2762 /* this is a heuristic to avoid seeking the dirptr except when
2763 absolutely necessary. It allows for a filename of about 40 chars */
2764 if (space_remaining < DIRLEN_GUESS && numentries > 0) {
2765 out_of_space = True;
2766 finished = False;
2767 } else {
2768 finished = !get_lanman2_dir_entry(ctx,
2769 conn,
2770 dirptr,
2771 req->flags2,
2772 mask,dirtype,info_level,
2773 requires_resume_key,dont_descend,
2774 ask_sharemode,
2775 &p,pdata,data_end,
2776 space_remaining, &out_of_space,
2777 &got_exact_match,
2778 &last_entry_off, ea_list);
2781 if (finished && out_of_space)
2782 finished = False;
2784 if (!finished && !out_of_space)
2785 numentries++;
2788 * As an optimisation if we know we aren't looking
2789 * for a wildcard name (ie. the name matches the wildcard exactly)
2790 * then we can finish on any (first) match.
2791 * This speeds up large directory searches. JRA.
2794 if(got_exact_match)
2795 finished = True;
2797 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
2800 DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
2801 smb_fn_name(req->cmd),
2802 mask, directory, dirtype, numentries ) );
2804 /* Check if we can close the dirptr */
2805 if(close_after_request || (finished && close_if_end)) {
2806 DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
2807 dptr_close(sconn, &dptr_num); /* This frees up the saved mask */
2810 /* Set up the return parameter block */
2811 SSVAL(params,0,numentries);
2812 SSVAL(params,2,finished);
2813 SSVAL(params,4,0); /* Never an EA error */
2814 SSVAL(params,6,last_entry_off);
2816 send_trans2_replies(conn, req, params, 8, pdata, PTR_DIFF(p,pdata),
2817 max_data_bytes);
2819 return;
2822 unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
2824 E_md4hash(lp_servicename(SNUM(conn)),objid);
2825 return objid;
2828 static void samba_extended_info_version(struct smb_extended_info *extended_info)
2830 SMB_ASSERT(extended_info != NULL);
2832 extended_info->samba_magic = SAMBA_EXTENDED_INFO_MAGIC;
2833 extended_info->samba_version = ((SAMBA_VERSION_MAJOR & 0xff) << 24)
2834 | ((SAMBA_VERSION_MINOR & 0xff) << 16)
2835 | ((SAMBA_VERSION_RELEASE & 0xff) << 8);
2836 #ifdef SAMBA_VERSION_REVISION
2837 extended_info->samba_version |= (tolower(*SAMBA_VERSION_REVISION) - 'a' + 1) & 0xff;
2838 #endif
2839 extended_info->samba_subversion = 0;
2840 #ifdef SAMBA_VERSION_RC_RELEASE
2841 extended_info->samba_subversion |= (SAMBA_VERSION_RC_RELEASE & 0xff) << 24;
2842 #else
2843 #ifdef SAMBA_VERSION_PRE_RELEASE
2844 extended_info->samba_subversion |= (SAMBA_VERSION_PRE_RELEASE & 0xff) << 16;
2845 #endif
2846 #endif
2847 #ifdef SAMBA_VERSION_VENDOR_PATCH
2848 extended_info->samba_subversion |= (SAMBA_VERSION_VENDOR_PATCH & 0xffff);
2849 #endif
2850 extended_info->samba_gitcommitdate = 0;
2851 #ifdef SAMBA_VERSION_GIT_COMMIT_TIME
2852 unix_to_nt_time(&extended_info->samba_gitcommitdate, SAMBA_VERSION_GIT_COMMIT_TIME);
2853 #endif
2855 memset(extended_info->samba_version_string, 0,
2856 sizeof(extended_info->samba_version_string));
2858 snprintf (extended_info->samba_version_string,
2859 sizeof(extended_info->samba_version_string),
2860 "%s", samba_version_string());
2863 NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
2864 TALLOC_CTX *mem_ctx,
2865 uint16_t info_level,
2866 uint16_t flags2,
2867 unsigned int max_data_bytes,
2868 char **ppdata,
2869 int *ret_data_len)
2871 char *pdata, *end_data;
2872 int data_len = 0, len;
2873 const char *vname = volume_label(SNUM(conn));
2874 int snum = SNUM(conn);
2875 char *fstype = lp_fstype(SNUM(conn));
2876 uint32 additional_flags = 0;
2877 struct smb_filename *smb_fname_dot = NULL;
2878 SMB_STRUCT_STAT st;
2879 NTSTATUS status;
2881 if (IS_IPC(conn)) {
2882 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
2883 DEBUG(0,("smbd_do_qfsinfo: not an allowed "
2884 "info level (0x%x) on IPC$.\n",
2885 (unsigned int)info_level));
2886 return NT_STATUS_ACCESS_DENIED;
2890 DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level));
2892 status = create_synthetic_smb_fname(talloc_tos(), ".", NULL, NULL,
2893 &smb_fname_dot);
2894 if (!NT_STATUS_IS_OK(status)) {
2895 return status;
2898 if(SMB_VFS_STAT(conn, smb_fname_dot) != 0) {
2899 DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
2900 TALLOC_FREE(smb_fname_dot);
2901 return map_nt_error_from_unix(errno);
2904 st = smb_fname_dot->st;
2905 TALLOC_FREE(smb_fname_dot);
2907 *ppdata = (char *)SMB_REALLOC(
2908 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2909 if (*ppdata == NULL) {
2910 return NT_STATUS_NO_MEMORY;
2913 pdata = *ppdata;
2914 memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2915 end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2917 switch (info_level) {
2918 case SMB_INFO_ALLOCATION:
2920 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
2921 data_len = 18;
2922 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
2923 return map_nt_error_from_unix(errno);
2926 block_size = lp_block_size(snum);
2927 if (bsize < block_size) {
2928 uint64_t factor = block_size/bsize;
2929 bsize = block_size;
2930 dsize /= factor;
2931 dfree /= factor;
2933 if (bsize > block_size) {
2934 uint64_t factor = bsize/block_size;
2935 bsize = block_size;
2936 dsize *= factor;
2937 dfree *= factor;
2939 bytes_per_sector = 512;
2940 sectors_per_unit = bsize/bytes_per_sector;
2942 DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
2943 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
2944 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2946 SIVAL(pdata,l1_idFileSystem,st.st_ex_dev);
2947 SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
2948 SIVAL(pdata,l1_cUnit,dsize);
2949 SIVAL(pdata,l1_cUnitAvail,dfree);
2950 SSVAL(pdata,l1_cbSector,bytes_per_sector);
2951 break;
2954 case SMB_INFO_VOLUME:
2955 /* Return volume name */
2957 * Add volume serial number - hash of a combination of
2958 * the called hostname and the service name.
2960 SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(get_local_machine_name())<<16) );
2962 * Win2k3 and previous mess this up by sending a name length
2963 * one byte short. I believe only older clients (OS/2 Win9x) use
2964 * this call so try fixing this by adding a terminating null to
2965 * the pushed string. The change here was adding the STR_TERMINATE. JRA.
2967 len = srvstr_push(
2968 pdata, flags2,
2969 pdata+l2_vol_szVolLabel, vname,
2970 PTR_DIFF(end_data, pdata+l2_vol_szVolLabel),
2971 STR_NOALIGN|STR_TERMINATE);
2972 SCVAL(pdata,l2_vol_cch,len);
2973 data_len = l2_vol_szVolLabel + len;
2974 DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %d, name = %s\n",
2975 (unsigned)convert_timespec_to_time_t(st.st_ex_ctime),
2976 len, vname));
2977 break;
2979 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2980 case SMB_FS_ATTRIBUTE_INFORMATION:
2982 additional_flags = 0;
2983 #if defined(HAVE_SYS_QUOTAS)
2984 additional_flags |= FILE_VOLUME_QUOTAS;
2985 #endif
2987 if(lp_nt_acl_support(SNUM(conn))) {
2988 additional_flags |= FILE_PERSISTENT_ACLS;
2991 /* Capabilities are filled in at connection time through STATVFS call */
2992 additional_flags |= conn->fs_capabilities;
2993 additional_flags |= lp_parm_int(conn->params->service,
2994 "share", "fake_fscaps",
2997 SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
2998 FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
2999 additional_flags); /* FS ATTRIBUTES */
3001 SIVAL(pdata,4,255); /* Max filename component length */
3002 /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
3003 and will think we can't do long filenames */
3004 len = srvstr_push(pdata, flags2, pdata+12, fstype,
3005 PTR_DIFF(end_data, pdata+12),
3006 STR_UNICODE);
3007 SIVAL(pdata,8,len);
3008 data_len = 12 + len;
3009 break;
3011 case SMB_QUERY_FS_LABEL_INFO:
3012 case SMB_FS_LABEL_INFORMATION:
3013 len = srvstr_push(pdata, flags2, pdata+4, vname,
3014 PTR_DIFF(end_data, pdata+4), 0);
3015 data_len = 4 + len;
3016 SIVAL(pdata,0,len);
3017 break;
3019 case SMB_QUERY_FS_VOLUME_INFO:
3020 case SMB_FS_VOLUME_INFORMATION:
3023 * Add volume serial number - hash of a combination of
3024 * the called hostname and the service name.
3026 SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^
3027 (str_checksum(get_local_machine_name())<<16));
3029 /* Max label len is 32 characters. */
3030 len = srvstr_push(pdata, flags2, pdata+18, vname,
3031 PTR_DIFF(end_data, pdata+18),
3032 STR_UNICODE);
3033 SIVAL(pdata,12,len);
3034 data_len = 18+len;
3036 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
3037 (int)strlen(vname),vname, lp_servicename(snum)));
3038 break;
3040 case SMB_QUERY_FS_SIZE_INFO:
3041 case SMB_FS_SIZE_INFORMATION:
3043 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
3044 data_len = 24;
3045 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
3046 return map_nt_error_from_unix(errno);
3048 block_size = lp_block_size(snum);
3049 if (bsize < block_size) {
3050 uint64_t factor = block_size/bsize;
3051 bsize = block_size;
3052 dsize /= factor;
3053 dfree /= factor;
3055 if (bsize > block_size) {
3056 uint64_t factor = bsize/block_size;
3057 bsize = block_size;
3058 dsize *= factor;
3059 dfree *= factor;
3061 bytes_per_sector = 512;
3062 sectors_per_unit = bsize/bytes_per_sector;
3063 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
3064 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
3065 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
3066 SBIG_UINT(pdata,0,dsize);
3067 SBIG_UINT(pdata,8,dfree);
3068 SIVAL(pdata,16,sectors_per_unit);
3069 SIVAL(pdata,20,bytes_per_sector);
3070 break;
3073 case SMB_FS_FULL_SIZE_INFORMATION:
3075 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
3076 data_len = 32;
3077 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
3078 return map_nt_error_from_unix(errno);
3080 block_size = lp_block_size(snum);
3081 if (bsize < block_size) {
3082 uint64_t factor = block_size/bsize;
3083 bsize = block_size;
3084 dsize /= factor;
3085 dfree /= factor;
3087 if (bsize > block_size) {
3088 uint64_t factor = bsize/block_size;
3089 bsize = block_size;
3090 dsize *= factor;
3091 dfree *= factor;
3093 bytes_per_sector = 512;
3094 sectors_per_unit = bsize/bytes_per_sector;
3095 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
3096 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
3097 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
3098 SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
3099 SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
3100 SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
3101 SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
3102 SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
3103 break;
3106 case SMB_QUERY_FS_DEVICE_INFO:
3107 case SMB_FS_DEVICE_INFORMATION:
3108 data_len = 8;
3109 SIVAL(pdata,0,0); /* dev type */
3110 SIVAL(pdata,4,0); /* characteristics */
3111 break;
3113 #ifdef HAVE_SYS_QUOTAS
3114 case SMB_FS_QUOTA_INFORMATION:
3116 * what we have to send --metze:
3118 * Unknown1: 24 NULL bytes
3119 * Soft Quota Treshold: 8 bytes seems like uint64_t or so
3120 * Hard Quota Limit: 8 bytes seems like uint64_t or so
3121 * Quota Flags: 2 byte :
3122 * Unknown3: 6 NULL bytes
3124 * 48 bytes total
3126 * details for Quota Flags:
3128 * 0x0020 Log Limit: log if the user exceeds his Hard Quota
3129 * 0x0010 Log Warn: log if the user exceeds his Soft Quota
3130 * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
3131 * 0x0001 Enable Quotas: enable quota for this fs
3135 /* we need to fake up a fsp here,
3136 * because its not send in this call
3138 files_struct fsp;
3139 SMB_NTQUOTA_STRUCT quotas;
3141 ZERO_STRUCT(fsp);
3142 ZERO_STRUCT(quotas);
3144 fsp.conn = conn;
3145 fsp.fnum = -1;
3147 /* access check */
3148 if (conn->server_info->utok.uid != sec_initial_uid()) {
3149 DEBUG(0,("set_user_quota: access_denied "
3150 "service [%s] user [%s]\n",
3151 lp_servicename(SNUM(conn)),
3152 conn->server_info->unix_name));
3153 return NT_STATUS_ACCESS_DENIED;
3156 if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
3157 DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3158 return map_nt_error_from_unix(errno);
3161 data_len = 48;
3163 DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",
3164 lp_servicename(SNUM(conn))));
3166 /* Unknown1 24 NULL bytes*/
3167 SBIG_UINT(pdata,0,(uint64_t)0);
3168 SBIG_UINT(pdata,8,(uint64_t)0);
3169 SBIG_UINT(pdata,16,(uint64_t)0);
3171 /* Default Soft Quota 8 bytes */
3172 SBIG_UINT(pdata,24,quotas.softlim);
3174 /* Default Hard Quota 8 bytes */
3175 SBIG_UINT(pdata,32,quotas.hardlim);
3177 /* Quota flag 2 bytes */
3178 SSVAL(pdata,40,quotas.qflags);
3180 /* Unknown3 6 NULL bytes */
3181 SSVAL(pdata,42,0);
3182 SIVAL(pdata,44,0);
3184 break;
3186 #endif /* HAVE_SYS_QUOTAS */
3187 case SMB_FS_OBJECTID_INFORMATION:
3189 unsigned char objid[16];
3190 struct smb_extended_info extended_info;
3191 memcpy(pdata,create_volume_objectid(conn, objid),16);
3192 samba_extended_info_version (&extended_info);
3193 SIVAL(pdata,16,extended_info.samba_magic);
3194 SIVAL(pdata,20,extended_info.samba_version);
3195 SIVAL(pdata,24,extended_info.samba_subversion);
3196 SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
3197 memcpy(pdata+36,extended_info.samba_version_string,28);
3198 data_len = 64;
3199 break;
3203 * Query the version and capabilities of the CIFS UNIX extensions
3204 * in use.
3207 case SMB_QUERY_CIFS_UNIX_INFO:
3209 bool large_write = lp_min_receive_file_size() &&
3210 !srv_is_signing_active(smbd_server_conn);
3211 bool large_read = !srv_is_signing_active(smbd_server_conn);
3212 int encrypt_caps = 0;
3214 if (!lp_unix_extensions()) {
3215 return NT_STATUS_INVALID_LEVEL;
3218 switch (conn->encrypt_level) {
3219 case 0:
3220 encrypt_caps = 0;
3221 break;
3222 case 1:
3223 case Auto:
3224 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
3225 break;
3226 case Required:
3227 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
3228 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
3229 large_write = false;
3230 large_read = false;
3231 break;
3234 data_len = 12;
3235 SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
3236 SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
3238 /* We have POSIX ACLs, pathname, encryption,
3239 * large read/write, and locking capability. */
3241 SBIG_UINT(pdata,4,((uint64_t)(
3242 CIFS_UNIX_POSIX_ACLS_CAP|
3243 CIFS_UNIX_POSIX_PATHNAMES_CAP|
3244 CIFS_UNIX_FCNTL_LOCKS_CAP|
3245 CIFS_UNIX_EXTATTR_CAP|
3246 CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
3247 encrypt_caps|
3248 (large_read ? CIFS_UNIX_LARGE_READ_CAP : 0) |
3249 (large_write ?
3250 CIFS_UNIX_LARGE_WRITE_CAP : 0))));
3251 break;
3254 case SMB_QUERY_POSIX_FS_INFO:
3256 int rc;
3257 vfs_statvfs_struct svfs;
3259 if (!lp_unix_extensions()) {
3260 return NT_STATUS_INVALID_LEVEL;
3263 rc = SMB_VFS_STATVFS(conn, ".", &svfs);
3265 if (!rc) {
3266 data_len = 56;
3267 SIVAL(pdata,0,svfs.OptimalTransferSize);
3268 SIVAL(pdata,4,svfs.BlockSize);
3269 SBIG_UINT(pdata,8,svfs.TotalBlocks);
3270 SBIG_UINT(pdata,16,svfs.BlocksAvail);
3271 SBIG_UINT(pdata,24,svfs.UserBlocksAvail);
3272 SBIG_UINT(pdata,32,svfs.TotalFileNodes);
3273 SBIG_UINT(pdata,40,svfs.FreeFileNodes);
3274 SBIG_UINT(pdata,48,svfs.FsIdentifier);
3275 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
3276 #ifdef EOPNOTSUPP
3277 } else if (rc == EOPNOTSUPP) {
3278 return NT_STATUS_INVALID_LEVEL;
3279 #endif /* EOPNOTSUPP */
3280 } else {
3281 DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3282 return NT_STATUS_DOS(ERRSRV, ERRerror);
3284 break;
3287 case SMB_QUERY_POSIX_WHOAMI:
3289 uint32_t flags = 0;
3290 uint32_t sid_bytes;
3291 int i;
3293 if (!lp_unix_extensions()) {
3294 return NT_STATUS_INVALID_LEVEL;
3297 if (max_data_bytes < 40) {
3298 return NT_STATUS_BUFFER_TOO_SMALL;
3301 /* We ARE guest if global_sid_Builtin_Guests is
3302 * in our list of SIDs.
3304 if (nt_token_check_sid(&global_sid_Builtin_Guests,
3305 conn->server_info->ptok)) {
3306 flags |= SMB_WHOAMI_GUEST;
3309 /* We are NOT guest if global_sid_Authenticated_Users
3310 * is in our list of SIDs.
3312 if (nt_token_check_sid(&global_sid_Authenticated_Users,
3313 conn->server_info->ptok)) {
3314 flags &= ~SMB_WHOAMI_GUEST;
3317 /* NOTE: 8 bytes for UID/GID, irrespective of native
3318 * platform size. This matches
3319 * SMB_QUERY_FILE_UNIX_BASIC and friends.
3321 data_len = 4 /* flags */
3322 + 4 /* flag mask */
3323 + 8 /* uid */
3324 + 8 /* gid */
3325 + 4 /* ngroups */
3326 + 4 /* num_sids */
3327 + 4 /* SID bytes */
3328 + 4 /* pad/reserved */
3329 + (conn->server_info->utok.ngroups * 8)
3330 /* groups list */
3331 + (conn->server_info->ptok->num_sids *
3332 SID_MAX_SIZE)
3333 /* SID list */;
3335 SIVAL(pdata, 0, flags);
3336 SIVAL(pdata, 4, SMB_WHOAMI_MASK);
3337 SBIG_UINT(pdata, 8,
3338 (uint64_t)conn->server_info->utok.uid);
3339 SBIG_UINT(pdata, 16,
3340 (uint64_t)conn->server_info->utok.gid);
3343 if (data_len >= max_data_bytes) {
3344 /* Potential overflow, skip the GIDs and SIDs. */
3346 SIVAL(pdata, 24, 0); /* num_groups */
3347 SIVAL(pdata, 28, 0); /* num_sids */
3348 SIVAL(pdata, 32, 0); /* num_sid_bytes */
3349 SIVAL(pdata, 36, 0); /* reserved */
3351 data_len = 40;
3352 break;
3355 SIVAL(pdata, 24, conn->server_info->utok.ngroups);
3356 SIVAL(pdata, 28, conn->server_info->num_sids);
3358 /* We walk the SID list twice, but this call is fairly
3359 * infrequent, and I don't expect that it's performance
3360 * sensitive -- jpeach
3362 for (i = 0, sid_bytes = 0;
3363 i < conn->server_info->ptok->num_sids; ++i) {
3364 sid_bytes += ndr_size_dom_sid(
3365 &conn->server_info->ptok->user_sids[i],
3366 NULL,
3370 /* SID list byte count */
3371 SIVAL(pdata, 32, sid_bytes);
3373 /* 4 bytes pad/reserved - must be zero */
3374 SIVAL(pdata, 36, 0);
3375 data_len = 40;
3377 /* GID list */
3378 for (i = 0; i < conn->server_info->utok.ngroups; ++i) {
3379 SBIG_UINT(pdata, data_len,
3380 (uint64_t)conn->server_info->utok.groups[i]);
3381 data_len += 8;
3384 /* SID list */
3385 for (i = 0;
3386 i < conn->server_info->ptok->num_sids; ++i) {
3387 int sid_len = ndr_size_dom_sid(
3388 &conn->server_info->ptok->user_sids[i],
3389 NULL,
3392 sid_linearize(pdata + data_len, sid_len,
3393 &conn->server_info->ptok->user_sids[i]);
3394 data_len += sid_len;
3397 break;
3400 case SMB_MAC_QUERY_FS_INFO:
3402 * Thursby MAC extension... ONLY on NTFS filesystems
3403 * once we do streams then we don't need this
3405 if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
3406 data_len = 88;
3407 SIVAL(pdata,84,0x100); /* Don't support mac... */
3408 break;
3410 /* drop through */
3411 default:
3412 return NT_STATUS_INVALID_LEVEL;
3415 *ret_data_len = data_len;
3416 return NT_STATUS_OK;
3419 /****************************************************************************
3420 Reply to a TRANS2_QFSINFO (query filesystem info).
3421 ****************************************************************************/
3423 static void call_trans2qfsinfo(connection_struct *conn,
3424 struct smb_request *req,
3425 char **pparams, int total_params,
3426 char **ppdata, int total_data,
3427 unsigned int max_data_bytes)
3429 char *params = *pparams;
3430 uint16_t info_level;
3431 int data_len = 0;
3432 NTSTATUS status;
3434 if (total_params < 2) {
3435 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3436 return;
3439 info_level = SVAL(params,0);
3441 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
3442 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
3443 DEBUG(0,("call_trans2qfsinfo: encryption required "
3444 "and info level 0x%x sent.\n",
3445 (unsigned int)info_level));
3446 exit_server_cleanly("encryption required "
3447 "on connection");
3448 return;
3452 DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
3454 status = smbd_do_qfsinfo(conn, req,
3455 info_level,
3456 req->flags2,
3457 max_data_bytes,
3458 ppdata, &data_len);
3459 if (!NT_STATUS_IS_OK(status)) {
3460 reply_nterror(req, status);
3461 return;
3464 send_trans2_replies(conn, req, params, 0, *ppdata, data_len,
3465 max_data_bytes);
3467 DEBUG( 4, ( "%s info_level = %d\n",
3468 smb_fn_name(req->cmd), info_level) );
3470 return;
3473 /****************************************************************************
3474 Reply to a TRANS2_SETFSINFO (set filesystem info).
3475 ****************************************************************************/
3477 static void call_trans2setfsinfo(connection_struct *conn,
3478 struct smb_request *req,
3479 char **pparams, int total_params,
3480 char **ppdata, int total_data,
3481 unsigned int max_data_bytes)
3483 char *pdata = *ppdata;
3484 char *params = *pparams;
3485 uint16 info_level;
3487 DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",lp_servicename(SNUM(conn))));
3489 /* */
3490 if (total_params < 4) {
3491 DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
3492 total_params));
3493 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3494 return;
3497 info_level = SVAL(params,2);
3499 if (IS_IPC(conn)) {
3500 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION &&
3501 info_level != SMB_SET_CIFS_UNIX_INFO) {
3502 DEBUG(0,("call_trans2setfsinfo: not an allowed "
3503 "info level (0x%x) on IPC$.\n",
3504 (unsigned int)info_level));
3505 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3506 return;
3510 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
3511 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION) {
3512 DEBUG(0,("call_trans2setfsinfo: encryption required "
3513 "and info level 0x%x sent.\n",
3514 (unsigned int)info_level));
3515 exit_server_cleanly("encryption required "
3516 "on connection");
3517 return;
3521 switch(info_level) {
3522 case SMB_SET_CIFS_UNIX_INFO:
3524 uint16 client_unix_major;
3525 uint16 client_unix_minor;
3526 uint32 client_unix_cap_low;
3527 uint32 client_unix_cap_high;
3529 if (!lp_unix_extensions()) {
3530 reply_nterror(req,
3531 NT_STATUS_INVALID_LEVEL);
3532 return;
3535 /* There should be 12 bytes of capabilities set. */
3536 if (total_data < 8) {
3537 reply_nterror(
3538 req,
3539 NT_STATUS_INVALID_PARAMETER);
3540 return;
3542 client_unix_major = SVAL(pdata,0);
3543 client_unix_minor = SVAL(pdata,2);
3544 client_unix_cap_low = IVAL(pdata,4);
3545 client_unix_cap_high = IVAL(pdata,8);
3546 /* Just print these values for now. */
3547 DEBUG(10,("call_trans2setfsinfo: set unix info. major = %u, minor = %u \
3548 cap_low = 0x%x, cap_high = 0x%x\n",
3549 (unsigned int)client_unix_major,
3550 (unsigned int)client_unix_minor,
3551 (unsigned int)client_unix_cap_low,
3552 (unsigned int)client_unix_cap_high ));
3554 /* Here is where we must switch to posix pathname processing... */
3555 if (client_unix_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3556 lp_set_posix_pathnames();
3557 mangle_change_to_posix();
3560 if ((client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) &&
3561 !(client_unix_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) {
3562 /* Client that knows how to do posix locks,
3563 * but not posix open/mkdir operations. Set a
3564 * default type for read/write checks. */
3566 lp_set_posix_default_cifsx_readwrite_locktype(POSIX_LOCK);
3569 break;
3572 case SMB_REQUEST_TRANSPORT_ENCRYPTION:
3574 NTSTATUS status;
3575 size_t param_len = 0;
3576 size_t data_len = total_data;
3578 if (!lp_unix_extensions()) {
3579 reply_nterror(
3580 req,
3581 NT_STATUS_INVALID_LEVEL);
3582 return;
3585 if (lp_smb_encrypt(SNUM(conn)) == false) {
3586 reply_nterror(
3587 req,
3588 NT_STATUS_NOT_SUPPORTED);
3589 return;
3592 DEBUG( 4,("call_trans2setfsinfo: "
3593 "request transport encryption.\n"));
3595 status = srv_request_encryption_setup(conn,
3596 (unsigned char **)ppdata,
3597 &data_len,
3598 (unsigned char **)pparams,
3599 &param_len);
3601 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
3602 !NT_STATUS_IS_OK(status)) {
3603 reply_nterror(req, status);
3604 return;
3607 send_trans2_replies(conn, req,
3608 *pparams,
3609 param_len,
3610 *ppdata,
3611 data_len,
3612 max_data_bytes);
3614 if (NT_STATUS_IS_OK(status)) {
3615 /* Server-side transport
3616 * encryption is now *on*. */
3617 status = srv_encryption_start(conn);
3618 if (!NT_STATUS_IS_OK(status)) {
3619 exit_server_cleanly(
3620 "Failure in setting "
3621 "up encrypted transport");
3624 return;
3627 case SMB_FS_QUOTA_INFORMATION:
3629 files_struct *fsp = NULL;
3630 SMB_NTQUOTA_STRUCT quotas;
3632 ZERO_STRUCT(quotas);
3634 /* access check */
3635 if ((conn->server_info->utok.uid != sec_initial_uid())
3636 ||!CAN_WRITE(conn)) {
3637 DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
3638 lp_servicename(SNUM(conn)),
3639 conn->server_info->unix_name));
3640 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3641 return;
3644 /* note: normaly there're 48 bytes,
3645 * but we didn't use the last 6 bytes for now
3646 * --metze
3648 fsp = file_fsp(req, SVAL(params,0));
3650 if (!check_fsp_ntquota_handle(conn, req,
3651 fsp)) {
3652 DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
3653 reply_nterror(
3654 req, NT_STATUS_INVALID_HANDLE);
3655 return;
3658 if (total_data < 42) {
3659 DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n",
3660 total_data));
3661 reply_nterror(
3662 req,
3663 NT_STATUS_INVALID_PARAMETER);
3664 return;
3667 /* unknown_1 24 NULL bytes in pdata*/
3669 /* the soft quotas 8 bytes (uint64_t)*/
3670 quotas.softlim = (uint64_t)IVAL(pdata,24);
3671 #ifdef LARGE_SMB_OFF_T
3672 quotas.softlim |= (((uint64_t)IVAL(pdata,28)) << 32);
3673 #else /* LARGE_SMB_OFF_T */
3674 if ((IVAL(pdata,28) != 0)&&
3675 ((quotas.softlim != 0xFFFFFFFF)||
3676 (IVAL(pdata,28)!=0xFFFFFFFF))) {
3677 /* more than 32 bits? */
3678 reply_nterror(
3679 req,
3680 NT_STATUS_INVALID_PARAMETER);
3681 return;
3683 #endif /* LARGE_SMB_OFF_T */
3685 /* the hard quotas 8 bytes (uint64_t)*/
3686 quotas.hardlim = (uint64_t)IVAL(pdata,32);
3687 #ifdef LARGE_SMB_OFF_T
3688 quotas.hardlim |= (((uint64_t)IVAL(pdata,36)) << 32);
3689 #else /* LARGE_SMB_OFF_T */
3690 if ((IVAL(pdata,36) != 0)&&
3691 ((quotas.hardlim != 0xFFFFFFFF)||
3692 (IVAL(pdata,36)!=0xFFFFFFFF))) {
3693 /* more than 32 bits? */
3694 reply_nterror(
3695 req,
3696 NT_STATUS_INVALID_PARAMETER);
3697 return;
3699 #endif /* LARGE_SMB_OFF_T */
3701 /* quota_flags 2 bytes **/
3702 quotas.qflags = SVAL(pdata,40);
3704 /* unknown_2 6 NULL bytes follow*/
3706 /* now set the quotas */
3707 if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
3708 DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3709 reply_nterror(req, map_nt_error_from_unix(errno));
3710 return;
3713 break;
3715 default:
3716 DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
3717 info_level));
3718 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
3719 return;
3720 break;
3724 * sending this reply works fine,
3725 * but I'm not sure it's the same
3726 * like windows do...
3727 * --metze
3729 reply_outbuf(req, 10, 0);
3732 #if defined(HAVE_POSIX_ACLS)
3733 /****************************************************************************
3734 Utility function to count the number of entries in a POSIX acl.
3735 ****************************************************************************/
3737 static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
3739 unsigned int ace_count = 0;
3740 int entry_id = SMB_ACL_FIRST_ENTRY;
3741 SMB_ACL_ENTRY_T entry;
3743 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
3744 /* get_next... */
3745 if (entry_id == SMB_ACL_FIRST_ENTRY) {
3746 entry_id = SMB_ACL_NEXT_ENTRY;
3748 ace_count++;
3750 return ace_count;
3753 /****************************************************************************
3754 Utility function to marshall a POSIX acl into wire format.
3755 ****************************************************************************/
3757 static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
3759 int entry_id = SMB_ACL_FIRST_ENTRY;
3760 SMB_ACL_ENTRY_T entry;
3762 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
3763 SMB_ACL_TAG_T tagtype;
3764 SMB_ACL_PERMSET_T permset;
3765 unsigned char perms = 0;
3766 unsigned int own_grp;
3768 /* get_next... */
3769 if (entry_id == SMB_ACL_FIRST_ENTRY) {
3770 entry_id = SMB_ACL_NEXT_ENTRY;
3773 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3774 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
3775 return False;
3778 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3779 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
3780 return False;
3783 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
3784 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
3785 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
3787 SCVAL(pdata,1,perms);
3789 switch (tagtype) {
3790 case SMB_ACL_USER_OBJ:
3791 SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
3792 own_grp = (unsigned int)pst->st_ex_uid;
3793 SIVAL(pdata,2,own_grp);
3794 SIVAL(pdata,6,0);
3795 break;
3796 case SMB_ACL_USER:
3798 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3799 if (!puid) {
3800 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
3801 return False;
3803 own_grp = (unsigned int)*puid;
3804 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
3805 SCVAL(pdata,0,SMB_POSIX_ACL_USER);
3806 SIVAL(pdata,2,own_grp);
3807 SIVAL(pdata,6,0);
3808 break;
3810 case SMB_ACL_GROUP_OBJ:
3811 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
3812 own_grp = (unsigned int)pst->st_ex_gid;
3813 SIVAL(pdata,2,own_grp);
3814 SIVAL(pdata,6,0);
3815 break;
3816 case SMB_ACL_GROUP:
3818 gid_t *pgid= (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3819 if (!pgid) {
3820 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
3821 return False;
3823 own_grp = (unsigned int)*pgid;
3824 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
3825 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
3826 SIVAL(pdata,2,own_grp);
3827 SIVAL(pdata,6,0);
3828 break;
3830 case SMB_ACL_MASK:
3831 SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
3832 SIVAL(pdata,2,0xFFFFFFFF);
3833 SIVAL(pdata,6,0xFFFFFFFF);
3834 break;
3835 case SMB_ACL_OTHER:
3836 SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
3837 SIVAL(pdata,2,0xFFFFFFFF);
3838 SIVAL(pdata,6,0xFFFFFFFF);
3839 break;
3840 default:
3841 DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
3842 return False;
3844 pdata += SMB_POSIX_ACL_ENTRY_SIZE;
3847 return True;
3849 #endif
3851 /****************************************************************************
3852 Store the FILE_UNIX_BASIC info.
3853 ****************************************************************************/
3855 static char *store_file_unix_basic(connection_struct *conn,
3856 char *pdata,
3857 files_struct *fsp,
3858 const SMB_STRUCT_STAT *psbuf)
3860 DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
3861 DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode));
3863 SOFF_T(pdata,0,get_file_size_stat(psbuf)); /* File size 64 Bit */
3864 pdata += 8;
3866 SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
3867 pdata += 8;
3869 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, psbuf->st_ex_ctime); /* Change Time 64 Bit */
3870 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, psbuf->st_ex_atime); /* Last access time 64 Bit */
3871 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, psbuf->st_ex_mtime); /* Last modification time 64 Bit */
3872 pdata += 24;
3874 SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */
3875 SIVAL(pdata,4,0);
3876 pdata += 8;
3878 SIVAL(pdata,0,psbuf->st_ex_gid); /* group id of owner */
3879 SIVAL(pdata,4,0);
3880 pdata += 8;
3882 SIVAL(pdata,0,unix_filetype(psbuf->st_ex_mode));
3883 pdata += 4;
3885 SIVAL(pdata,0,unix_dev_major(psbuf->st_ex_rdev)); /* Major device number if type is device */
3886 SIVAL(pdata,4,0);
3887 pdata += 8;
3889 SIVAL(pdata,0,unix_dev_minor(psbuf->st_ex_rdev)); /* Minor device number if type is device */
3890 SIVAL(pdata,4,0);
3891 pdata += 8;
3893 SINO_T_VAL(pdata,0,(SMB_INO_T)psbuf->st_ex_ino); /* inode number */
3894 pdata += 8;
3896 SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode)); /* Standard UNIX file permissions */
3897 SIVAL(pdata,4,0);
3898 pdata += 8;
3900 SIVAL(pdata,0,psbuf->st_ex_nlink); /* number of hard links */
3901 SIVAL(pdata,4,0);
3902 pdata += 8;
3904 return pdata;
3907 /* Forward and reverse mappings from the UNIX_INFO2 file flags field and
3908 * the chflags(2) (or equivalent) flags.
3910 * XXX: this really should be behind the VFS interface. To do this, we would
3911 * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field.
3912 * Each VFS module could then implement its own mapping as appropriate for the
3913 * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS.
3915 static const struct {unsigned stat_fflag; unsigned smb_fflag;}
3916 info2_flags_map[] =
3918 #ifdef UF_NODUMP
3919 { UF_NODUMP, EXT_DO_NOT_BACKUP },
3920 #endif
3922 #ifdef UF_IMMUTABLE
3923 { UF_IMMUTABLE, EXT_IMMUTABLE },
3924 #endif
3926 #ifdef UF_APPEND
3927 { UF_APPEND, EXT_OPEN_APPEND_ONLY },
3928 #endif
3930 #ifdef UF_HIDDEN
3931 { UF_HIDDEN, EXT_HIDDEN },
3932 #endif
3934 /* Do not remove. We need to guarantee that this array has at least one
3935 * entry to build on HP-UX.
3937 { 0, 0 }
3941 static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
3942 uint32 *smb_fflags, uint32 *smb_fmask)
3944 int i;
3946 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3947 *smb_fmask |= info2_flags_map[i].smb_fflag;
3948 if (psbuf->st_ex_flags & info2_flags_map[i].stat_fflag) {
3949 *smb_fflags |= info2_flags_map[i].smb_fflag;
3954 static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
3955 const uint32 smb_fflags,
3956 const uint32 smb_fmask,
3957 int *stat_fflags)
3959 uint32 max_fmask = 0;
3960 int i;
3962 *stat_fflags = psbuf->st_ex_flags;
3964 /* For each flags requested in smb_fmask, check the state of the
3965 * corresponding flag in smb_fflags and set or clear the matching
3966 * stat flag.
3969 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3970 max_fmask |= info2_flags_map[i].smb_fflag;
3971 if (smb_fmask & info2_flags_map[i].smb_fflag) {
3972 if (smb_fflags & info2_flags_map[i].smb_fflag) {
3973 *stat_fflags |= info2_flags_map[i].stat_fflag;
3974 } else {
3975 *stat_fflags &= ~info2_flags_map[i].stat_fflag;
3980 /* If smb_fmask is asking to set any bits that are not supported by
3981 * our flag mappings, we should fail.
3983 if ((smb_fmask & max_fmask) != smb_fmask) {
3984 return False;
3987 return True;
3991 /* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition
3992 * of file flags and birth (create) time.
3994 static char *store_file_unix_basic_info2(connection_struct *conn,
3995 char *pdata,
3996 files_struct *fsp,
3997 const SMB_STRUCT_STAT *psbuf)
3999 uint32 file_flags = 0;
4000 uint32 flags_mask = 0;
4002 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
4004 /* Create (birth) time 64 bit */
4005 put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, psbuf->st_ex_btime);
4006 pdata += 8;
4008 map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
4009 SIVAL(pdata, 0, file_flags); /* flags */
4010 SIVAL(pdata, 4, flags_mask); /* mask */
4011 pdata += 8;
4013 return pdata;
4016 static NTSTATUS marshall_stream_info(unsigned int num_streams,
4017 const struct stream_struct *streams,
4018 char *data,
4019 unsigned int max_data_bytes,
4020 unsigned int *data_size)
4022 unsigned int i;
4023 unsigned int ofs = 0;
4025 for (i = 0; i < num_streams && ofs <= max_data_bytes; i++) {
4026 unsigned int next_offset;
4027 size_t namelen;
4028 smb_ucs2_t *namebuf;
4030 if (!push_ucs2_talloc(talloc_tos(), &namebuf,
4031 streams[i].name, &namelen) ||
4032 namelen <= 2)
4034 return NT_STATUS_INVALID_PARAMETER;
4038 * name_buf is now null-terminated, we need to marshall as not
4039 * terminated
4042 namelen -= 2;
4044 SIVAL(data, ofs+4, namelen);
4045 SOFF_T(data, ofs+8, streams[i].size);
4046 SOFF_T(data, ofs+16, streams[i].alloc_size);
4047 memcpy(data+ofs+24, namebuf, namelen);
4048 TALLOC_FREE(namebuf);
4050 next_offset = ofs + 24 + namelen;
4052 if (i == num_streams-1) {
4053 SIVAL(data, ofs, 0);
4055 else {
4056 unsigned int align = ndr_align_size(next_offset, 8);
4058 memset(data+next_offset, 0, align);
4059 next_offset += align;
4061 SIVAL(data, ofs, next_offset - ofs);
4062 ofs = next_offset;
4065 ofs = next_offset;
4068 *data_size = ofs;
4070 return NT_STATUS_OK;
4073 /****************************************************************************
4074 Reply to a TRANSACT2_QFILEINFO on a PIPE !
4075 ****************************************************************************/
4077 static void call_trans2qpipeinfo(connection_struct *conn,
4078 struct smb_request *req,
4079 unsigned int tran_call,
4080 char **pparams, int total_params,
4081 char **ppdata, int total_data,
4082 unsigned int max_data_bytes)
4084 char *params = *pparams;
4085 char *pdata = *ppdata;
4086 unsigned int data_size = 0;
4087 unsigned int param_size = 2;
4088 uint16 info_level;
4089 files_struct *fsp;
4091 if (!params) {
4092 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4093 return;
4096 if (total_params < 4) {
4097 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4098 return;
4101 fsp = file_fsp(req, SVAL(params,0));
4102 if (!fsp_is_np(fsp)) {
4103 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4104 return;
4107 info_level = SVAL(params,2);
4109 *pparams = (char *)SMB_REALLOC(*pparams,2);
4110 if (*pparams == NULL) {
4111 reply_nterror(req, NT_STATUS_NO_MEMORY);
4112 return;
4114 params = *pparams;
4115 SSVAL(params,0,0);
4116 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
4117 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
4118 if (*ppdata == NULL ) {
4119 reply_nterror(req, NT_STATUS_NO_MEMORY);
4120 return;
4122 pdata = *ppdata;
4124 switch (info_level) {
4125 case SMB_FILE_STANDARD_INFORMATION:
4126 memset(pdata,0,24);
4127 SOFF_T(pdata,0,4096LL);
4128 SIVAL(pdata,16,1);
4129 SIVAL(pdata,20,1);
4130 data_size = 24;
4131 break;
4133 default:
4134 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4135 return;
4138 send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
4139 max_data_bytes);
4141 return;
4144 NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
4145 TALLOC_CTX *mem_ctx,
4146 uint16_t info_level,
4147 files_struct *fsp,
4148 struct smb_filename *smb_fname,
4149 bool delete_pending,
4150 struct timespec write_time_ts,
4151 bool ms_dfs_link,
4152 struct ea_list *ea_list,
4153 int lock_data_count,
4154 char *lock_data,
4155 uint16_t flags2,
4156 unsigned int max_data_bytes,
4157 char **ppdata,
4158 unsigned int *pdata_size)
4160 char *pdata = *ppdata;
4161 char *dstart, *dend;
4162 unsigned int data_size;
4163 struct timespec create_time_ts, mtime_ts, atime_ts, ctime_ts;
4164 time_t create_time, mtime, atime, c_time;
4165 SMB_STRUCT_STAT *psbuf = &smb_fname->st;
4166 char *p;
4167 char *base_name;
4168 char *dos_fname;
4169 int mode;
4170 int nlink;
4171 NTSTATUS status;
4172 uint64_t file_size = 0;
4173 uint64_t pos = 0;
4174 uint64_t allocation_size = 0;
4175 uint64_t file_index = 0;
4176 uint32_t access_mask = 0;
4178 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
4179 return NT_STATUS_INVALID_LEVEL;
4182 DEBUG(5,("smbd_do_qfilepathinfo: %s (fnum = %d) level=%d max_data=%u\n",
4183 smb_fname_str_dbg(smb_fname), fsp ? fsp->fnum : -1,
4184 info_level, max_data_bytes));
4186 if (ms_dfs_link) {
4187 mode = dos_mode_msdfs(conn, smb_fname);
4188 } else {
4189 mode = dos_mode(conn, smb_fname);
4191 if (!mode)
4192 mode = FILE_ATTRIBUTE_NORMAL;
4194 nlink = psbuf->st_ex_nlink;
4196 if (nlink && (mode&aDIR)) {
4197 nlink = 1;
4200 if ((nlink > 0) && delete_pending) {
4201 nlink -= 1;
4204 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
4205 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
4206 if (*ppdata == NULL) {
4207 return NT_STATUS_NO_MEMORY;
4209 pdata = *ppdata;
4210 dstart = pdata;
4211 dend = dstart + data_size - 1;
4213 if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) {
4214 update_stat_ex_mtime(psbuf, write_time_ts);
4217 create_time_ts = get_create_timespec(conn, fsp, smb_fname);
4218 mtime_ts = psbuf->st_ex_mtime;
4219 atime_ts = psbuf->st_ex_atime;
4220 ctime_ts = get_change_timespec(conn, fsp, smb_fname);
4222 if (lp_dos_filetime_resolution(SNUM(conn))) {
4223 dos_filetime_timespec(&create_time_ts);
4224 dos_filetime_timespec(&mtime_ts);
4225 dos_filetime_timespec(&atime_ts);
4226 dos_filetime_timespec(&ctime_ts);
4229 create_time = convert_timespec_to_time_t(create_time_ts);
4230 mtime = convert_timespec_to_time_t(mtime_ts);
4231 atime = convert_timespec_to_time_t(atime_ts);
4232 c_time = convert_timespec_to_time_t(ctime_ts);
4234 p = strrchr_m(smb_fname->base_name,'/');
4235 if (!p)
4236 base_name = smb_fname->base_name;
4237 else
4238 base_name = p+1;
4240 /* NT expects the name to be in an exact form of the *full*
4241 filename. See the trans2 torture test */
4242 if (ISDOT(base_name)) {
4243 dos_fname = talloc_strdup(mem_ctx, "\\");
4244 if (!dos_fname) {
4245 return NT_STATUS_NO_MEMORY;
4247 } else {
4248 dos_fname = talloc_asprintf(mem_ctx,
4249 "\\%s",
4250 smb_fname->base_name);
4251 if (!dos_fname) {
4252 return NT_STATUS_NO_MEMORY;
4254 if (is_ntfs_stream_smb_fname(smb_fname)) {
4255 dos_fname = talloc_asprintf(dos_fname, "%s",
4256 smb_fname->stream_name);
4257 if (!dos_fname) {
4258 return NT_STATUS_NO_MEMORY;
4262 string_replace(dos_fname, '/', '\\');
4265 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, psbuf);
4267 if (!fsp) {
4268 /* Do we have this path open ? */
4269 files_struct *fsp1;
4270 struct file_id fileid = vfs_file_id_from_sbuf(conn, psbuf);
4271 fsp1 = file_find_di_first(fileid);
4272 if (fsp1 && fsp1->initial_allocation_size) {
4273 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, psbuf);
4277 if (!(mode & aDIR)) {
4278 file_size = get_file_size_stat(psbuf);
4281 if (fsp) {
4282 pos = fsp->fh->position_information;
4285 if (fsp) {
4286 access_mask = fsp->access_mask;
4287 } else {
4288 /* GENERIC_EXECUTE mapping from Windows */
4289 access_mask = 0x12019F;
4292 /* This should be an index number - looks like
4293 dev/ino to me :-)
4295 I think this causes us to fail the IFSKIT
4296 BasicFileInformationTest. -tpot */
4297 file_index = ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */
4298 file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */
4300 switch (info_level) {
4301 case SMB_INFO_STANDARD:
4302 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
4303 data_size = 22;
4304 srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
4305 srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
4306 srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
4307 SIVAL(pdata,l1_cbFile,(uint32)file_size);
4308 SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
4309 SSVAL(pdata,l1_attrFile,mode);
4310 break;
4312 case SMB_INFO_QUERY_EA_SIZE:
4314 unsigned int ea_size =
4315 estimate_ea_size(conn, fsp,
4316 smb_fname->base_name);
4317 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
4318 data_size = 26;
4319 srv_put_dos_date2(pdata,0,create_time);
4320 srv_put_dos_date2(pdata,4,atime);
4321 srv_put_dos_date2(pdata,8,mtime); /* write time */
4322 SIVAL(pdata,12,(uint32)file_size);
4323 SIVAL(pdata,16,(uint32)allocation_size);
4324 SSVAL(pdata,20,mode);
4325 SIVAL(pdata,22,ea_size);
4326 break;
4329 case SMB_INFO_IS_NAME_VALID:
4330 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
4331 if (fsp) {
4332 /* os/2 needs this ? really ?*/
4333 return NT_STATUS_DOS(ERRDOS, ERRbadfunc);
4335 /* This is only reached for qpathinfo */
4336 data_size = 0;
4337 break;
4339 case SMB_INFO_QUERY_EAS_FROM_LIST:
4341 size_t total_ea_len = 0;
4342 struct ea_list *ea_file_list = NULL;
4344 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
4346 ea_file_list =
4347 get_ea_list_from_file(mem_ctx, conn, fsp,
4348 smb_fname->base_name,
4349 &total_ea_len);
4350 ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
4352 if (!ea_list || (total_ea_len > data_size)) {
4353 data_size = 4;
4354 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
4355 break;
4358 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
4359 break;
4362 case SMB_INFO_QUERY_ALL_EAS:
4364 /* We have data_size bytes to put EA's into. */
4365 size_t total_ea_len = 0;
4367 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
4369 ea_list = get_ea_list_from_file(mem_ctx, conn, fsp,
4370 smb_fname->base_name,
4371 &total_ea_len);
4372 if (!ea_list || (total_ea_len > data_size)) {
4373 data_size = 4;
4374 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
4375 break;
4378 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
4379 break;
4382 case 0xFF0F:/*SMB2_INFO_QUERY_ALL_EAS*/
4384 /* This is FileFullEaInformation - 0xF which maps to
4385 * 1015 (decimal) in smbd_do_setfilepathinfo. */
4387 /* We have data_size bytes to put EA's into. */
4388 size_t total_ea_len = 0;
4389 struct ea_list *ea_file_list = NULL;
4391 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n"));
4393 /*TODO: add filtering and index handling */
4395 ea_file_list =
4396 get_ea_list_from_file(mem_ctx, conn, fsp,
4397 smb_fname->base_name,
4398 &total_ea_len);
4399 if (!ea_file_list) {
4400 return NT_STATUS_NO_EAS_ON_FILE;
4403 status = fill_ea_chained_buffer(mem_ctx,
4404 pdata,
4405 data_size,
4406 &data_size,
4407 conn, ea_file_list);
4408 if (!NT_STATUS_IS_OK(status)) {
4409 return status;
4411 break;
4414 case SMB_FILE_BASIC_INFORMATION:
4415 case SMB_QUERY_FILE_BASIC_INFO:
4417 if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
4418 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
4419 data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
4420 } else {
4421 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
4422 data_size = 40;
4423 SIVAL(pdata,36,0);
4425 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
4426 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
4427 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
4428 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
4429 SIVAL(pdata,32,mode);
4431 DEBUG(5,("SMB_QFBI - "));
4432 DEBUG(5,("create: %s ", ctime(&create_time)));
4433 DEBUG(5,("access: %s ", ctime(&atime)));
4434 DEBUG(5,("write: %s ", ctime(&mtime)));
4435 DEBUG(5,("change: %s ", ctime(&c_time)));
4436 DEBUG(5,("mode: %x\n", mode));
4437 break;
4439 case SMB_FILE_STANDARD_INFORMATION:
4440 case SMB_QUERY_FILE_STANDARD_INFO:
4442 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
4443 data_size = 24;
4444 SOFF_T(pdata,0,allocation_size);
4445 SOFF_T(pdata,8,file_size);
4446 SIVAL(pdata,16,nlink);
4447 SCVAL(pdata,20,delete_pending?1:0);
4448 SCVAL(pdata,21,(mode&aDIR)?1:0);
4449 SSVAL(pdata,22,0); /* Padding. */
4450 break;
4452 case SMB_FILE_EA_INFORMATION:
4453 case SMB_QUERY_FILE_EA_INFO:
4455 unsigned int ea_size =
4456 estimate_ea_size(conn, fsp, smb_fname->base_name);
4457 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
4458 data_size = 4;
4459 SIVAL(pdata,0,ea_size);
4460 break;
4463 /* Get the 8.3 name - used if NT SMB was negotiated. */
4464 case SMB_QUERY_FILE_ALT_NAME_INFO:
4465 case SMB_FILE_ALTERNATE_NAME_INFORMATION:
4467 int len;
4468 char mangled_name[13];
4469 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
4470 if (!name_to_8_3(base_name,mangled_name,
4471 True,conn->params)) {
4472 return NT_STATUS_NO_MEMORY;
4474 len = srvstr_push(dstart, flags2,
4475 pdata+4, mangled_name,
4476 PTR_DIFF(dend, pdata+4),
4477 STR_UNICODE);
4478 data_size = 4 + len;
4479 SIVAL(pdata,0,len);
4480 break;
4483 case SMB_QUERY_FILE_NAME_INFO:
4485 int len;
4487 this must be *exactly* right for ACLs on mapped drives to work
4489 len = srvstr_push(dstart, flags2,
4490 pdata+4, dos_fname,
4491 PTR_DIFF(dend, pdata+4),
4492 STR_UNICODE);
4493 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
4494 data_size = 4 + len;
4495 SIVAL(pdata,0,len);
4496 break;
4499 case SMB_FILE_ALLOCATION_INFORMATION:
4500 case SMB_QUERY_FILE_ALLOCATION_INFO:
4501 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
4502 data_size = 8;
4503 SOFF_T(pdata,0,allocation_size);
4504 break;
4506 case SMB_FILE_END_OF_FILE_INFORMATION:
4507 case SMB_QUERY_FILE_END_OF_FILEINFO:
4508 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
4509 data_size = 8;
4510 SOFF_T(pdata,0,file_size);
4511 break;
4513 case SMB_QUERY_FILE_ALL_INFO:
4514 case SMB_FILE_ALL_INFORMATION:
4516 int len;
4517 unsigned int ea_size =
4518 estimate_ea_size(conn, fsp, smb_fname->base_name);
4519 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
4520 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
4521 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
4522 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
4523 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
4524 SIVAL(pdata,32,mode);
4525 SIVAL(pdata,36,0); /* padding. */
4526 pdata += 40;
4527 SOFF_T(pdata,0,allocation_size);
4528 SOFF_T(pdata,8,file_size);
4529 SIVAL(pdata,16,nlink);
4530 SCVAL(pdata,20,delete_pending);
4531 SCVAL(pdata,21,(mode&aDIR)?1:0);
4532 SSVAL(pdata,22,0);
4533 pdata += 24;
4534 SIVAL(pdata,0,ea_size);
4535 pdata += 4; /* EA info */
4536 len = srvstr_push(dstart, flags2,
4537 pdata+4, dos_fname,
4538 PTR_DIFF(dend, pdata+4),
4539 STR_UNICODE);
4540 SIVAL(pdata,0,len);
4541 pdata += 4 + len;
4542 data_size = PTR_DIFF(pdata,(*ppdata));
4543 break;
4546 case 0xFF12:/*SMB2_FILE_ALL_INFORMATION*/
4548 int len;
4549 unsigned int ea_size =
4550 estimate_ea_size(conn, fsp, smb_fname->base_name);
4551 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
4552 put_long_date_timespec(conn->ts_res,pdata+0x00,create_time_ts);
4553 put_long_date_timespec(conn->ts_res,pdata+0x08,atime_ts);
4554 put_long_date_timespec(conn->ts_res,pdata+0x10,mtime_ts); /* write time */
4555 put_long_date_timespec(conn->ts_res,pdata+0x18,ctime_ts); /* change time */
4556 SIVAL(pdata, 0x20, mode);
4557 SIVAL(pdata, 0x24, 0); /* padding. */
4558 SBVAL(pdata, 0x28, allocation_size);
4559 SBVAL(pdata, 0x30, file_size);
4560 SIVAL(pdata, 0x38, nlink);
4561 SCVAL(pdata, 0x3C, delete_pending);
4562 SCVAL(pdata, 0x3D, (mode&aDIR)?1:0);
4563 SSVAL(pdata, 0x3E, 0); /* padding */
4564 SBVAL(pdata, 0x40, file_index);
4565 SIVAL(pdata, 0x48, ea_size);
4566 SIVAL(pdata, 0x4C, access_mask);
4567 SBVAL(pdata, 0x50, pos);
4568 SIVAL(pdata, 0x58, mode); /*TODO: mode != mode fix this!!! */
4569 SIVAL(pdata, 0x5C, 0); /* No alignment needed. */
4571 pdata += 0x60;
4573 len = srvstr_push(dstart, flags2,
4574 pdata+4, dos_fname,
4575 PTR_DIFF(dend, pdata+4),
4576 STR_UNICODE);
4577 SIVAL(pdata,0,len);
4578 pdata += 4 + len;
4579 data_size = PTR_DIFF(pdata,(*ppdata));
4580 break;
4582 case SMB_FILE_INTERNAL_INFORMATION:
4584 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
4585 SBVAL(pdata, 0, file_index);
4586 data_size = 8;
4587 break;
4589 case SMB_FILE_ACCESS_INFORMATION:
4590 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
4591 SIVAL(pdata, 0, access_mask);
4592 data_size = 4;
4593 break;
4595 case SMB_FILE_NAME_INFORMATION:
4596 /* Pathname with leading '\'. */
4598 size_t byte_len;
4599 byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
4600 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
4601 SIVAL(pdata,0,byte_len);
4602 data_size = 4 + byte_len;
4603 break;
4606 case SMB_FILE_DISPOSITION_INFORMATION:
4607 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
4608 data_size = 1;
4609 SCVAL(pdata,0,delete_pending);
4610 break;
4612 case SMB_FILE_POSITION_INFORMATION:
4613 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
4614 data_size = 8;
4615 SOFF_T(pdata,0,pos);
4616 break;
4618 case SMB_FILE_MODE_INFORMATION:
4619 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
4620 SIVAL(pdata,0,mode);
4621 data_size = 4;
4622 break;
4624 case SMB_FILE_ALIGNMENT_INFORMATION:
4625 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
4626 SIVAL(pdata,0,0); /* No alignment needed. */
4627 data_size = 4;
4628 break;
4631 * NT4 server just returns "invalid query" to this - if we try
4632 * to answer it then NTws gets a BSOD! (tridge). W2K seems to
4633 * want this. JRA.
4635 /* The first statement above is false - verified using Thursby
4636 * client against NT4 -- gcolley.
4638 case SMB_QUERY_FILE_STREAM_INFO:
4639 case SMB_FILE_STREAM_INFORMATION: {
4640 unsigned int num_streams;
4641 struct stream_struct *streams;
4643 DEBUG(10,("smbd_do_qfilepathinfo: "
4644 "SMB_FILE_STREAM_INFORMATION\n"));
4646 if (is_ntfs_stream_smb_fname(smb_fname)) {
4647 return NT_STATUS_INVALID_PARAMETER;
4650 status = SMB_VFS_STREAMINFO(
4651 conn, fsp, smb_fname->base_name, talloc_tos(),
4652 &num_streams, &streams);
4654 if (!NT_STATUS_IS_OK(status)) {
4655 DEBUG(10, ("could not get stream info: %s\n",
4656 nt_errstr(status)));
4657 return status;
4660 status = marshall_stream_info(num_streams, streams,
4661 pdata, max_data_bytes,
4662 &data_size);
4664 if (!NT_STATUS_IS_OK(status)) {
4665 DEBUG(10, ("marshall_stream_info failed: %s\n",
4666 nt_errstr(status)));
4667 return status;
4670 TALLOC_FREE(streams);
4672 break;
4674 case SMB_QUERY_COMPRESSION_INFO:
4675 case SMB_FILE_COMPRESSION_INFORMATION:
4676 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
4677 SOFF_T(pdata,0,file_size);
4678 SIVAL(pdata,8,0); /* ??? */
4679 SIVAL(pdata,12,0); /* ??? */
4680 data_size = 16;
4681 break;
4683 case SMB_FILE_NETWORK_OPEN_INFORMATION:
4684 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
4685 put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
4686 put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
4687 put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
4688 put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
4689 SOFF_T(pdata,32,allocation_size);
4690 SOFF_T(pdata,40,file_size);
4691 SIVAL(pdata,48,mode);
4692 SIVAL(pdata,52,0); /* ??? */
4693 data_size = 56;
4694 break;
4696 case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
4697 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
4698 SIVAL(pdata,0,mode);
4699 SIVAL(pdata,4,0);
4700 data_size = 8;
4701 break;
4704 * CIFS UNIX Extensions.
4707 case SMB_QUERY_FILE_UNIX_BASIC:
4709 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
4710 data_size = PTR_DIFF(pdata,(*ppdata));
4713 int i;
4714 DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC "));
4716 for (i=0; i<100; i++)
4717 DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
4718 DEBUG(4,("\n"));
4721 break;
4723 case SMB_QUERY_FILE_UNIX_INFO2:
4725 pdata = store_file_unix_basic_info2(conn, pdata, fsp, psbuf);
4726 data_size = PTR_DIFF(pdata,(*ppdata));
4729 int i;
4730 DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));
4732 for (i=0; i<100; i++)
4733 DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
4734 DEBUG(4,("\n"));
4737 break;
4739 case SMB_QUERY_FILE_UNIX_LINK:
4741 int len;
4742 char *buffer = TALLOC_ARRAY(mem_ctx, char, PATH_MAX+1);
4744 if (!buffer) {
4745 return NT_STATUS_NO_MEMORY;
4748 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n"));
4749 #ifdef S_ISLNK
4750 if(!S_ISLNK(psbuf->st_ex_mode)) {
4751 return NT_STATUS_DOS(ERRSRV, ERRbadlink);
4753 #else
4754 return NT_STATUS_DOS(ERRDOS, ERRbadlink);
4755 #endif
4756 len = SMB_VFS_READLINK(conn,
4757 smb_fname->base_name,
4758 buffer, PATH_MAX);
4759 if (len == -1) {
4760 return map_nt_error_from_unix(errno);
4762 buffer[len] = 0;
4763 len = srvstr_push(dstart, flags2,
4764 pdata, buffer,
4765 PTR_DIFF(dend, pdata),
4766 STR_TERMINATE);
4767 pdata += len;
4768 data_size = PTR_DIFF(pdata,(*ppdata));
4770 break;
4773 #if defined(HAVE_POSIX_ACLS)
4774 case SMB_QUERY_POSIX_ACL:
4776 SMB_ACL_T file_acl = NULL;
4777 SMB_ACL_T def_acl = NULL;
4778 uint16 num_file_acls = 0;
4779 uint16 num_def_acls = 0;
4781 if (fsp && !fsp->is_directory && (fsp->fh->fd != -1)) {
4782 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
4783 } else {
4784 file_acl =
4785 SMB_VFS_SYS_ACL_GET_FILE(conn,
4786 smb_fname->base_name,
4787 SMB_ACL_TYPE_ACCESS);
4790 if (file_acl == NULL && no_acl_syscall_error(errno)) {
4791 DEBUG(5,("smbd_do_qfilepathinfo: ACLs "
4792 "not implemented on "
4793 "filesystem containing %s\n",
4794 smb_fname->base_name));
4795 return NT_STATUS_NOT_IMPLEMENTED;
4798 if (S_ISDIR(psbuf->st_ex_mode)) {
4799 if (fsp && fsp->is_directory) {
4800 def_acl =
4801 SMB_VFS_SYS_ACL_GET_FILE(
4802 conn,
4803 fsp->fsp_name->base_name,
4804 SMB_ACL_TYPE_DEFAULT);
4805 } else {
4806 def_acl =
4807 SMB_VFS_SYS_ACL_GET_FILE(
4808 conn,
4809 smb_fname->base_name,
4810 SMB_ACL_TYPE_DEFAULT);
4812 def_acl = free_empty_sys_acl(conn, def_acl);
4815 num_file_acls = count_acl_entries(conn, file_acl);
4816 num_def_acls = count_acl_entries(conn, def_acl);
4818 if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) {
4819 DEBUG(5,("smbd_do_qfilepathinfo: data_size too small (%u) need %u\n",
4820 data_size,
4821 (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
4822 SMB_POSIX_ACL_HEADER_SIZE) ));
4823 if (file_acl) {
4824 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4826 if (def_acl) {
4827 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4829 return NT_STATUS_BUFFER_TOO_SMALL;
4832 SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
4833 SSVAL(pdata,2,num_file_acls);
4834 SSVAL(pdata,4,num_def_acls);
4835 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, psbuf, file_acl)) {
4836 if (file_acl) {
4837 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4839 if (def_acl) {
4840 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4842 return NT_STATUS_INTERNAL_ERROR;
4844 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), psbuf, def_acl)) {
4845 if (file_acl) {
4846 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4848 if (def_acl) {
4849 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4851 return NT_STATUS_INTERNAL_ERROR;
4854 if (file_acl) {
4855 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4857 if (def_acl) {
4858 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4860 data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
4861 break;
4863 #endif
4866 case SMB_QUERY_POSIX_LOCK:
4868 uint64_t count;
4869 uint64_t offset;
4870 uint32 lock_pid;
4871 enum brl_type lock_type;
4873 /* We need an open file with a real fd for this. */
4874 if (!fsp || fsp->is_directory || fsp->fh->fd == -1) {
4875 return NT_STATUS_INVALID_LEVEL;
4878 if (lock_data_count != POSIX_LOCK_DATA_SIZE) {
4879 return NT_STATUS_INVALID_PARAMETER;
4882 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
4883 case POSIX_LOCK_TYPE_READ:
4884 lock_type = READ_LOCK;
4885 break;
4886 case POSIX_LOCK_TYPE_WRITE:
4887 lock_type = WRITE_LOCK;
4888 break;
4889 case POSIX_LOCK_TYPE_UNLOCK:
4890 default:
4891 /* There's no point in asking for an unlock... */
4892 return NT_STATUS_INVALID_PARAMETER;
4895 lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
4896 #if defined(HAVE_LONGLONG)
4897 offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
4898 ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
4899 count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
4900 ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
4901 #else /* HAVE_LONGLONG */
4902 offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET);
4903 count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
4904 #endif /* HAVE_LONGLONG */
4906 status = query_lock(fsp,
4907 &lock_pid,
4908 &count,
4909 &offset,
4910 &lock_type,
4911 POSIX_LOCK);
4913 if (ERROR_WAS_LOCK_DENIED(status)) {
4914 /* Here we need to report who has it locked... */
4915 data_size = POSIX_LOCK_DATA_SIZE;
4917 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
4918 SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
4919 SIVAL(pdata, POSIX_LOCK_PID_OFFSET, lock_pid);
4920 #if defined(HAVE_LONGLONG)
4921 SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF));
4922 SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF));
4923 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF));
4924 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF));
4925 #else /* HAVE_LONGLONG */
4926 SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
4927 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
4928 #endif /* HAVE_LONGLONG */
4930 } else if (NT_STATUS_IS_OK(status)) {
4931 /* For success we just return a copy of what we sent
4932 with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
4933 data_size = POSIX_LOCK_DATA_SIZE;
4934 memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
4935 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
4936 } else {
4937 return status;
4939 break;
4942 default:
4943 return NT_STATUS_INVALID_LEVEL;
4946 *pdata_size = data_size;
4947 return NT_STATUS_OK;
4950 /****************************************************************************
4951 Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
4952 file name or file id).
4953 ****************************************************************************/
4955 static void call_trans2qfilepathinfo(connection_struct *conn,
4956 struct smb_request *req,
4957 unsigned int tran_call,
4958 char **pparams, int total_params,
4959 char **ppdata, int total_data,
4960 unsigned int max_data_bytes)
4962 char *params = *pparams;
4963 char *pdata = *ppdata;
4964 uint16 info_level;
4965 unsigned int data_size = 0;
4966 unsigned int param_size = 2;
4967 struct smb_filename *smb_fname = NULL;
4968 bool delete_pending = False;
4969 struct timespec write_time_ts;
4970 files_struct *fsp = NULL;
4971 struct file_id fileid;
4972 struct ea_list *ea_list = NULL;
4973 int lock_data_count = 0;
4974 char *lock_data = NULL;
4975 bool ms_dfs_link = false;
4976 NTSTATUS status = NT_STATUS_OK;
4978 if (!params) {
4979 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4980 return;
4983 ZERO_STRUCT(write_time_ts);
4985 if (tran_call == TRANSACT2_QFILEINFO) {
4986 if (total_params < 4) {
4987 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4988 return;
4991 if (IS_IPC(conn)) {
4992 call_trans2qpipeinfo(conn, req, tran_call,
4993 pparams, total_params,
4994 ppdata, total_data,
4995 max_data_bytes);
4996 return;
4999 fsp = file_fsp(req, SVAL(params,0));
5000 info_level = SVAL(params,2);
5002 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
5004 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
5005 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5006 return;
5009 /* Initial check for valid fsp ptr. */
5010 if (!check_fsp_open(conn, req, fsp)) {
5011 return;
5014 status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
5015 &smb_fname);
5016 if (!NT_STATUS_IS_OK(status)) {
5017 reply_nterror(req, status);
5018 return;
5021 if(fsp->fake_file_handle) {
5023 * This is actually for the QUOTA_FAKE_FILE --metze
5026 /* We know this name is ok, it's already passed the checks. */
5028 } else if(fsp->is_directory || fsp->fh->fd == -1) {
5030 * This is actually a QFILEINFO on a directory
5031 * handle (returned from an NT SMB). NT5.0 seems
5032 * to do this call. JRA.
5035 if (INFO_LEVEL_IS_UNIX(info_level)) {
5036 /* Always do lstat for UNIX calls. */
5037 if (SMB_VFS_LSTAT(conn, smb_fname)) {
5038 DEBUG(3,("call_trans2qfilepathinfo: "
5039 "SMB_VFS_LSTAT of %s failed "
5040 "(%s)\n",
5041 smb_fname_str_dbg(smb_fname),
5042 strerror(errno)));
5043 reply_nterror(req,
5044 map_nt_error_from_unix(errno));
5045 return;
5047 } else if (SMB_VFS_STAT(conn, smb_fname)) {
5048 DEBUG(3,("call_trans2qfilepathinfo: "
5049 "SMB_VFS_STAT of %s failed (%s)\n",
5050 smb_fname_str_dbg(smb_fname),
5051 strerror(errno)));
5052 reply_nterror(req,
5053 map_nt_error_from_unix(errno));
5054 return;
5057 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5058 get_file_infos(fileid, &delete_pending, &write_time_ts);
5059 } else {
5061 * Original code - this is an open file.
5063 if (!check_fsp(conn, req, fsp)) {
5064 return;
5067 if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
5068 DEBUG(3, ("fstat of fnum %d failed (%s)\n",
5069 fsp->fnum, strerror(errno)));
5070 reply_nterror(req,
5071 map_nt_error_from_unix(errno));
5072 return;
5074 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5075 get_file_infos(fileid, &delete_pending, &write_time_ts);
5078 } else {
5079 char *fname = NULL;
5081 /* qpathinfo */
5082 if (total_params < 7) {
5083 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5084 return;
5087 info_level = SVAL(params,0);
5089 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
5091 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
5092 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5093 return;
5096 srvstr_get_path(req, params, req->flags2, &fname, &params[6],
5097 total_params - 6,
5098 STR_TERMINATE, &status);
5099 if (!NT_STATUS_IS_OK(status)) {
5100 reply_nterror(req, status);
5101 return;
5104 status = filename_convert(req,
5105 conn,
5106 req->flags2 & FLAGS2_DFS_PATHNAMES,
5107 fname,
5109 NULL,
5110 &smb_fname);
5111 if (!NT_STATUS_IS_OK(status)) {
5112 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5113 reply_botherror(req,
5114 NT_STATUS_PATH_NOT_COVERED,
5115 ERRSRV, ERRbadpath);
5116 return;
5118 reply_nterror(req, status);
5119 return;
5122 /* If this is a stream, check if there is a delete_pending. */
5123 if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
5124 && is_ntfs_stream_smb_fname(smb_fname)) {
5125 struct smb_filename *smb_fname_base = NULL;
5127 /* Create an smb_filename with stream_name == NULL. */
5128 status =
5129 create_synthetic_smb_fname(talloc_tos(),
5130 smb_fname->base_name,
5131 NULL, NULL,
5132 &smb_fname_base);
5133 if (!NT_STATUS_IS_OK(status)) {
5134 reply_nterror(req, status);
5135 return;
5138 if (INFO_LEVEL_IS_UNIX(info_level)) {
5139 /* Always do lstat for UNIX calls. */
5140 if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) {
5141 DEBUG(3,("call_trans2qfilepathinfo: "
5142 "SMB_VFS_LSTAT of %s failed "
5143 "(%s)\n",
5144 smb_fname_str_dbg(smb_fname_base),
5145 strerror(errno)));
5146 TALLOC_FREE(smb_fname_base);
5147 reply_nterror(req,
5148 map_nt_error_from_unix(errno));
5149 return;
5151 } else {
5152 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
5153 DEBUG(3,("call_trans2qfilepathinfo: "
5154 "fileinfo of %s failed "
5155 "(%s)\n",
5156 smb_fname_str_dbg(smb_fname_base),
5157 strerror(errno)));
5158 TALLOC_FREE(smb_fname_base);
5159 reply_nterror(req,
5160 map_nt_error_from_unix(errno));
5161 return;
5165 fileid = vfs_file_id_from_sbuf(conn,
5166 &smb_fname_base->st);
5167 TALLOC_FREE(smb_fname_base);
5168 get_file_infos(fileid, &delete_pending, NULL);
5169 if (delete_pending) {
5170 reply_nterror(req, NT_STATUS_DELETE_PENDING);
5171 return;
5175 if (INFO_LEVEL_IS_UNIX(info_level)) {
5176 /* Always do lstat for UNIX calls. */
5177 if (SMB_VFS_LSTAT(conn, smb_fname)) {
5178 DEBUG(3,("call_trans2qfilepathinfo: "
5179 "SMB_VFS_LSTAT of %s failed (%s)\n",
5180 smb_fname_str_dbg(smb_fname),
5181 strerror(errno)));
5182 reply_nterror(req,
5183 map_nt_error_from_unix(errno));
5184 return;
5187 } else if (!VALID_STAT(smb_fname->st) &&
5188 SMB_VFS_STAT(conn, smb_fname) &&
5189 (info_level != SMB_INFO_IS_NAME_VALID)) {
5190 ms_dfs_link = check_msdfs_link(conn,
5191 smb_fname->base_name,
5192 &smb_fname->st);
5194 if (!ms_dfs_link) {
5195 DEBUG(3,("call_trans2qfilepathinfo: "
5196 "SMB_VFS_STAT of %s failed (%s)\n",
5197 smb_fname_str_dbg(smb_fname),
5198 strerror(errno)));
5199 reply_nterror(req,
5200 map_nt_error_from_unix(errno));
5201 return;
5205 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5206 get_file_infos(fileid, &delete_pending, &write_time_ts);
5207 if (delete_pending) {
5208 reply_nterror(req, NT_STATUS_DELETE_PENDING);
5209 return;
5213 DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d "
5214 "total_data=%d\n", smb_fname_str_dbg(smb_fname),
5215 fsp ? fsp->fnum : -1, info_level,tran_call,total_data));
5217 /* Pull out any data sent here before we realloc. */
5218 switch (info_level) {
5219 case SMB_INFO_QUERY_EAS_FROM_LIST:
5221 /* Pull any EA list from the data portion. */
5222 uint32 ea_size;
5224 if (total_data < 4) {
5225 reply_nterror(
5226 req, NT_STATUS_INVALID_PARAMETER);
5227 return;
5229 ea_size = IVAL(pdata,0);
5231 if (total_data > 0 && ea_size != total_data) {
5232 DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
5233 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
5234 reply_nterror(
5235 req, NT_STATUS_INVALID_PARAMETER);
5236 return;
5239 if (!lp_ea_support(SNUM(conn))) {
5240 reply_doserror(req, ERRDOS,
5241 ERReasnotsupported);
5242 return;
5245 /* Pull out the list of names. */
5246 ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4);
5247 if (!ea_list) {
5248 reply_nterror(
5249 req, NT_STATUS_INVALID_PARAMETER);
5250 return;
5252 break;
5255 case SMB_QUERY_POSIX_LOCK:
5257 if (fsp == NULL || fsp->fh->fd == -1) {
5258 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5259 return;
5262 if (total_data != POSIX_LOCK_DATA_SIZE) {
5263 reply_nterror(
5264 req, NT_STATUS_INVALID_PARAMETER);
5265 return;
5268 /* Copy the lock range data. */
5269 lock_data = (char *)TALLOC_MEMDUP(
5270 req, pdata, total_data);
5271 if (!lock_data) {
5272 reply_nterror(req, NT_STATUS_NO_MEMORY);
5273 return;
5275 lock_data_count = total_data;
5277 default:
5278 break;
5281 *pparams = (char *)SMB_REALLOC(*pparams,2);
5282 if (*pparams == NULL) {
5283 reply_nterror(req, NT_STATUS_NO_MEMORY);
5284 return;
5286 params = *pparams;
5287 SSVAL(params,0,0);
5290 * draft-leach-cifs-v1-spec-02.txt
5291 * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path
5292 * says:
5294 * The requested information is placed in the Data portion of the
5295 * transaction response. For the information levels greater than 0x100,
5296 * the transaction response has 1 parameter word which should be
5297 * ignored by the client.
5299 * However Windows only follows this rule for the IS_NAME_VALID call.
5301 switch (info_level) {
5302 case SMB_INFO_IS_NAME_VALID:
5303 param_size = 0;
5304 break;
5307 if ((info_level & 0xFF00) == 0xFF00) {
5309 * We use levels that start with 0xFF00
5310 * internally to represent SMB2 specific levels
5312 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5313 return;
5316 status = smbd_do_qfilepathinfo(conn, req, info_level,
5317 fsp, smb_fname,
5318 delete_pending, write_time_ts,
5319 ms_dfs_link, ea_list,
5320 lock_data_count, lock_data,
5321 req->flags2, max_data_bytes,
5322 ppdata, &data_size);
5323 if (!NT_STATUS_IS_OK(status)) {
5324 reply_nterror(req, status);
5325 return;
5328 send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
5329 max_data_bytes);
5331 return;
5334 /****************************************************************************
5335 Set a hard link (called by UNIX extensions and by NT rename with HARD link
5336 code.
5337 ****************************************************************************/
5339 NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
5340 connection_struct *conn,
5341 const struct smb_filename *smb_fname_old,
5342 const struct smb_filename *smb_fname_new)
5344 NTSTATUS status = NT_STATUS_OK;
5346 /* source must already exist. */
5347 if (!VALID_STAT(smb_fname_old->st)) {
5348 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5351 /* Disallow if newname already exists. */
5352 if (VALID_STAT(smb_fname_new->st)) {
5353 return NT_STATUS_OBJECT_NAME_COLLISION;
5356 /* No links from a directory. */
5357 if (S_ISDIR(smb_fname_old->st.st_ex_mode)) {
5358 return NT_STATUS_FILE_IS_A_DIRECTORY;
5361 /* Setting a hardlink to/from a stream isn't currently supported. */
5362 if (is_ntfs_stream_smb_fname(smb_fname_old) ||
5363 is_ntfs_stream_smb_fname(smb_fname_new)) {
5364 return NT_STATUS_INVALID_PARAMETER;
5367 DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n",
5368 smb_fname_old->base_name, smb_fname_new->base_name));
5370 if (SMB_VFS_LINK(conn, smb_fname_old->base_name,
5371 smb_fname_new->base_name) != 0) {
5372 status = map_nt_error_from_unix(errno);
5373 DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
5374 nt_errstr(status), smb_fname_old->base_name,
5375 smb_fname_new->base_name));
5377 return status;
5380 /****************************************************************************
5381 Deal with setting the time from any of the setfilepathinfo functions.
5382 ****************************************************************************/
5384 NTSTATUS smb_set_file_time(connection_struct *conn,
5385 files_struct *fsp,
5386 const struct smb_filename *smb_fname,
5387 struct smb_file_time *ft,
5388 bool setting_write_time)
5390 struct smb_filename *smb_fname_base = NULL;
5391 uint32 action =
5392 FILE_NOTIFY_CHANGE_LAST_ACCESS
5393 |FILE_NOTIFY_CHANGE_LAST_WRITE
5394 |FILE_NOTIFY_CHANGE_CREATION;
5395 NTSTATUS status;
5397 if (!VALID_STAT(smb_fname->st)) {
5398 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5401 /* get some defaults (no modifications) if any info is zero or -1. */
5402 if (null_timespec(ft->create_time)) {
5403 action &= ~FILE_NOTIFY_CHANGE_CREATION;
5406 if (null_timespec(ft->atime)) {
5407 action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
5410 if (null_timespec(ft->mtime)) {
5411 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
5414 if (!setting_write_time) {
5415 /* ft->mtime comes from change time, not write time. */
5416 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
5419 /* Ensure the resolution is the correct for
5420 * what we can store on this filesystem. */
5422 round_timespec(conn->ts_res, &ft->create_time);
5423 round_timespec(conn->ts_res, &ft->ctime);
5424 round_timespec(conn->ts_res, &ft->atime);
5425 round_timespec(conn->ts_res, &ft->mtime);
5427 DEBUG(5,("smb_set_filetime: actime: %s\n ",
5428 time_to_asc(convert_timespec_to_time_t(ft->atime))));
5429 DEBUG(5,("smb_set_filetime: modtime: %s\n ",
5430 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
5431 DEBUG(5,("smb_set_filetime: ctime: %s\n ",
5432 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
5433 DEBUG(5,("smb_set_file_time: createtime: %s\n ",
5434 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
5436 if (setting_write_time) {
5438 * This was a Windows setfileinfo on an open file.
5439 * NT does this a lot. We also need to
5440 * set the time here, as it can be read by
5441 * FindFirst/FindNext and with the patch for bug #2045
5442 * in smbd/fileio.c it ensures that this timestamp is
5443 * kept sticky even after a write. We save the request
5444 * away and will set it on file close and after a write. JRA.
5447 DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n",
5448 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
5450 if (fsp != NULL) {
5451 if (fsp->base_fsp) {
5452 set_sticky_write_time_fsp(fsp->base_fsp,
5453 ft->mtime);
5454 } else {
5455 set_sticky_write_time_fsp(fsp, ft->mtime);
5457 } else {
5458 set_sticky_write_time_path(
5459 vfs_file_id_from_sbuf(conn, &smb_fname->st),
5460 ft->mtime);
5464 DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
5466 /* Always call ntimes on the base, even if a stream was passed in. */
5467 status = create_synthetic_smb_fname(talloc_tos(), smb_fname->base_name,
5468 NULL, &smb_fname->st,
5469 &smb_fname_base);
5470 if (!NT_STATUS_IS_OK(status)) {
5471 return status;
5474 if(file_ntimes(conn, smb_fname_base, ft)!=0) {
5475 TALLOC_FREE(smb_fname_base);
5476 return map_nt_error_from_unix(errno);
5478 TALLOC_FREE(smb_fname_base);
5480 notify_fname(conn, NOTIFY_ACTION_MODIFIED, action,
5481 smb_fname->base_name);
5482 return NT_STATUS_OK;
5485 /****************************************************************************
5486 Deal with setting the dosmode from any of the setfilepathinfo functions.
5487 ****************************************************************************/
5489 static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
5490 const struct smb_filename *smb_fname,
5491 uint32 dosmode)
5493 struct smb_filename *smb_fname_base = NULL;
5494 NTSTATUS status;
5496 if (!VALID_STAT(smb_fname->st)) {
5497 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5500 /* Always operate on the base_name, even if a stream was passed in. */
5501 status = create_synthetic_smb_fname(talloc_tos(), smb_fname->base_name,
5502 NULL, &smb_fname->st,
5503 &smb_fname_base);
5504 if (!NT_STATUS_IS_OK(status)) {
5505 return status;
5508 if (dosmode) {
5509 if (S_ISDIR(smb_fname_base->st.st_ex_mode)) {
5510 dosmode |= aDIR;
5511 } else {
5512 dosmode &= ~aDIR;
5516 DEBUG(6,("smb_set_file_dosmode: dosmode: 0x%x\n", (unsigned int)dosmode));
5518 /* check the mode isn't different, before changing it */
5519 if ((dosmode != 0) && (dosmode != dos_mode(conn, smb_fname_base))) {
5520 DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode "
5521 "0x%x\n", smb_fname_str_dbg(smb_fname_base),
5522 (unsigned int)dosmode));
5524 if(file_set_dosmode(conn, smb_fname_base, dosmode, NULL,
5525 false)) {
5526 DEBUG(2,("smb_set_file_dosmode: file_set_dosmode of "
5527 "%s failed (%s)\n",
5528 smb_fname_str_dbg(smb_fname_base),
5529 strerror(errno)));
5530 status = map_nt_error_from_unix(errno);
5531 goto out;
5534 status = NT_STATUS_OK;
5535 out:
5536 TALLOC_FREE(smb_fname_base);
5537 return status;
5540 /****************************************************************************
5541 Deal with setting the size from any of the setfilepathinfo functions.
5542 ****************************************************************************/
5544 static NTSTATUS smb_set_file_size(connection_struct *conn,
5545 struct smb_request *req,
5546 files_struct *fsp,
5547 const struct smb_filename *smb_fname,
5548 const SMB_STRUCT_STAT *psbuf,
5549 SMB_OFF_T size)
5551 NTSTATUS status = NT_STATUS_OK;
5552 struct smb_filename *smb_fname_tmp = NULL;
5553 files_struct *new_fsp = NULL;
5555 if (!VALID_STAT(*psbuf)) {
5556 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5559 DEBUG(6,("smb_set_file_size: size: %.0f ", (double)size));
5561 if (size == get_file_size_stat(psbuf)) {
5562 return NT_STATUS_OK;
5565 DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n",
5566 smb_fname_str_dbg(smb_fname), (double)size));
5568 if (fsp && fsp->fh->fd != -1) {
5569 /* Handle based call. */
5570 if (vfs_set_filelen(fsp, size) == -1) {
5571 return map_nt_error_from_unix(errno);
5573 trigger_write_time_update_immediate(fsp);
5574 return NT_STATUS_OK;
5577 status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
5578 if (!NT_STATUS_IS_OK(status)) {
5579 return status;
5582 smb_fname_tmp->st = *psbuf;
5584 status = SMB_VFS_CREATE_FILE(
5585 conn, /* conn */
5586 req, /* req */
5587 0, /* root_dir_fid */
5588 smb_fname_tmp, /* fname */
5589 FILE_WRITE_ATTRIBUTES, /* access_mask */
5590 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5591 FILE_SHARE_DELETE),
5592 FILE_OPEN, /* create_disposition*/
5593 0, /* create_options */
5594 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
5595 FORCE_OPLOCK_BREAK_TO_NONE, /* oplock_request */
5596 0, /* allocation_size */
5597 NULL, /* sd */
5598 NULL, /* ea_list */
5599 &new_fsp, /* result */
5600 NULL); /* pinfo */
5602 TALLOC_FREE(smb_fname_tmp);
5604 if (!NT_STATUS_IS_OK(status)) {
5605 /* NB. We check for open_was_deferred in the caller. */
5606 return status;
5609 if (vfs_set_filelen(new_fsp, size) == -1) {
5610 status = map_nt_error_from_unix(errno);
5611 close_file(req, new_fsp,NORMAL_CLOSE);
5612 return status;
5615 trigger_write_time_update_immediate(new_fsp);
5616 close_file(req, new_fsp,NORMAL_CLOSE);
5617 return NT_STATUS_OK;
5620 /****************************************************************************
5621 Deal with SMB_INFO_SET_EA.
5622 ****************************************************************************/
5624 static NTSTATUS smb_info_set_ea(connection_struct *conn,
5625 const char *pdata,
5626 int total_data,
5627 files_struct *fsp,
5628 const struct smb_filename *smb_fname)
5630 struct ea_list *ea_list = NULL;
5631 TALLOC_CTX *ctx = NULL;
5632 NTSTATUS status = NT_STATUS_OK;
5634 if (total_data < 10) {
5636 /* OS/2 workplace shell seems to send SET_EA requests of "null"
5637 length. They seem to have no effect. Bug #3212. JRA */
5639 if ((total_data == 4) && (IVAL(pdata,0) == 4)) {
5640 /* We're done. We only get EA info in this call. */
5641 return NT_STATUS_OK;
5644 return NT_STATUS_INVALID_PARAMETER;
5647 if (IVAL(pdata,0) > total_data) {
5648 DEBUG(10,("smb_info_set_ea: bad total data size (%u) > %u\n",
5649 IVAL(pdata,0), (unsigned int)total_data));
5650 return NT_STATUS_INVALID_PARAMETER;
5653 ctx = talloc_tos();
5654 ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
5655 if (!ea_list) {
5656 return NT_STATUS_INVALID_PARAMETER;
5658 status = set_ea(conn, fsp, smb_fname, ea_list);
5660 return status;
5663 /****************************************************************************
5664 Deal with SMB_FILE_FULL_EA_INFORMATION set.
5665 ****************************************************************************/
5667 static NTSTATUS smb_set_file_full_ea_info(connection_struct *conn,
5668 const char *pdata,
5669 int total_data,
5670 files_struct *fsp)
5672 struct ea_list *ea_list = NULL;
5673 NTSTATUS status;
5675 if (!fsp) {
5676 return NT_STATUS_INVALID_HANDLE;
5679 if (!lp_ea_support(SNUM(conn))) {
5680 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u but "
5681 "EA's not supported.\n",
5682 (unsigned int)total_data));
5683 return NT_STATUS_EAS_NOT_SUPPORTED;
5686 if (total_data < 10) {
5687 DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u "
5688 "too small.\n",
5689 (unsigned int)total_data));
5690 return NT_STATUS_INVALID_PARAMETER;
5693 ea_list = read_nttrans_ea_list(talloc_tos(),
5694 pdata,
5695 total_data);
5697 if (!ea_list) {
5698 return NT_STATUS_INVALID_PARAMETER;
5700 status = set_ea(conn, fsp, fsp->fsp_name, ea_list);
5702 DEBUG(10, ("smb_set_file_full_ea_info on file %s returned %s\n",
5703 smb_fname_str_dbg(fsp->fsp_name),
5704 nt_errstr(status) ));
5706 return status;
5710 /****************************************************************************
5711 Deal with SMB_SET_FILE_DISPOSITION_INFO.
5712 ****************************************************************************/
5714 static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
5715 const char *pdata,
5716 int total_data,
5717 files_struct *fsp,
5718 const struct smb_filename *smb_fname)
5720 NTSTATUS status = NT_STATUS_OK;
5721 bool delete_on_close;
5722 uint32 dosmode = 0;
5724 if (total_data < 1) {
5725 return NT_STATUS_INVALID_PARAMETER;
5728 if (fsp == NULL) {
5729 return NT_STATUS_INVALID_HANDLE;
5732 delete_on_close = (CVAL(pdata,0) ? True : False);
5733 dosmode = dos_mode(conn, smb_fname);
5735 DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
5736 "delete_on_close = %u\n",
5737 smb_fname_str_dbg(smb_fname),
5738 (unsigned int)dosmode,
5739 (unsigned int)delete_on_close ));
5741 status = can_set_delete_on_close(fsp, delete_on_close, dosmode);
5743 if (!NT_STATUS_IS_OK(status)) {
5744 return status;
5747 /* The set is across all open files on this dev/inode pair. */
5748 if (!set_delete_on_close(fsp, delete_on_close,
5749 &conn->server_info->utok)) {
5750 return NT_STATUS_ACCESS_DENIED;
5752 return NT_STATUS_OK;
5755 /****************************************************************************
5756 Deal with SMB_FILE_POSITION_INFORMATION.
5757 ****************************************************************************/
5759 static NTSTATUS smb_file_position_information(connection_struct *conn,
5760 const char *pdata,
5761 int total_data,
5762 files_struct *fsp)
5764 uint64_t position_information;
5766 if (total_data < 8) {
5767 return NT_STATUS_INVALID_PARAMETER;
5770 if (fsp == NULL) {
5771 /* Ignore on pathname based set. */
5772 return NT_STATUS_OK;
5775 position_information = (uint64_t)IVAL(pdata,0);
5776 #ifdef LARGE_SMB_OFF_T
5777 position_information |= (((uint64_t)IVAL(pdata,4)) << 32);
5778 #else /* LARGE_SMB_OFF_T */
5779 if (IVAL(pdata,4) != 0) {
5780 /* more than 32 bits? */
5781 return NT_STATUS_INVALID_PARAMETER;
5783 #endif /* LARGE_SMB_OFF_T */
5785 DEBUG(10,("smb_file_position_information: Set file position "
5786 "information for file %s to %.0f\n", fsp_str_dbg(fsp),
5787 (double)position_information));
5788 fsp->fh->position_information = position_information;
5789 return NT_STATUS_OK;
5792 /****************************************************************************
5793 Deal with SMB_FILE_MODE_INFORMATION.
5794 ****************************************************************************/
5796 static NTSTATUS smb_file_mode_information(connection_struct *conn,
5797 const char *pdata,
5798 int total_data)
5800 uint32 mode;
5802 if (total_data < 4) {
5803 return NT_STATUS_INVALID_PARAMETER;
5805 mode = IVAL(pdata,0);
5806 if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
5807 return NT_STATUS_INVALID_PARAMETER;
5809 return NT_STATUS_OK;
5812 /****************************************************************************
5813 Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
5814 ****************************************************************************/
5816 static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
5817 struct smb_request *req,
5818 const char *pdata,
5819 int total_data,
5820 const struct smb_filename *smb_fname)
5822 char *link_target = NULL;
5823 const char *newname = smb_fname->base_name;
5824 NTSTATUS status = NT_STATUS_OK;
5825 TALLOC_CTX *ctx = talloc_tos();
5827 /* Set a symbolic link. */
5828 /* Don't allow this if follow links is false. */
5830 if (total_data == 0) {
5831 return NT_STATUS_INVALID_PARAMETER;
5834 if (!lp_symlinks(SNUM(conn))) {
5835 return NT_STATUS_ACCESS_DENIED;
5838 srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
5839 total_data, STR_TERMINATE);
5841 if (!link_target) {
5842 return NT_STATUS_INVALID_PARAMETER;
5845 /* !widelinks forces the target path to be within the share. */
5846 /* This means we can interpret the target as a pathname. */
5847 if (!lp_widelinks(SNUM(conn))) {
5848 char *rel_name = NULL;
5849 char *last_dirp = NULL;
5851 if (*link_target == '/') {
5852 /* No absolute paths allowed. */
5853 return NT_STATUS_ACCESS_DENIED;
5855 rel_name = talloc_strdup(ctx,newname);
5856 if (!rel_name) {
5857 return NT_STATUS_NO_MEMORY;
5859 last_dirp = strrchr_m(rel_name, '/');
5860 if (last_dirp) {
5861 last_dirp[1] = '\0';
5862 } else {
5863 rel_name = talloc_strdup(ctx,"./");
5864 if (!rel_name) {
5865 return NT_STATUS_NO_MEMORY;
5868 rel_name = talloc_asprintf_append(rel_name,
5869 "%s",
5870 link_target);
5871 if (!rel_name) {
5872 return NT_STATUS_NO_MEMORY;
5875 status = check_name(conn, rel_name);
5876 if (!NT_STATUS_IS_OK(status)) {
5877 return status;
5881 DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
5882 newname, link_target ));
5884 if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0) {
5885 return map_nt_error_from_unix(errno);
5888 return NT_STATUS_OK;
5891 /****************************************************************************
5892 Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
5893 ****************************************************************************/
5895 static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
5896 struct smb_request *req,
5897 const char *pdata, int total_data,
5898 const struct smb_filename *smb_fname_new)
5900 char *oldname = NULL;
5901 struct smb_filename *smb_fname_old = NULL;
5902 TALLOC_CTX *ctx = talloc_tos();
5903 NTSTATUS status = NT_STATUS_OK;
5905 /* Set a hard link. */
5906 if (total_data == 0) {
5907 return NT_STATUS_INVALID_PARAMETER;
5910 srvstr_get_path(ctx, pdata, req->flags2, &oldname, pdata,
5911 total_data, STR_TERMINATE, &status);
5912 if (!NT_STATUS_IS_OK(status)) {
5913 return status;
5916 DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
5917 smb_fname_str_dbg(smb_fname_new), oldname));
5919 status = filename_convert(ctx,
5920 conn,
5921 req->flags2 & FLAGS2_DFS_PATHNAMES,
5922 oldname,
5924 NULL,
5925 &smb_fname_old);
5926 if (!NT_STATUS_IS_OK(status)) {
5927 return status;
5930 return hardlink_internals(ctx, conn, smb_fname_old, smb_fname_new);
5933 /****************************************************************************
5934 Deal with SMB_FILE_RENAME_INFORMATION.
5935 ****************************************************************************/
5937 static NTSTATUS smb_file_rename_information(connection_struct *conn,
5938 struct smb_request *req,
5939 const char *pdata,
5940 int total_data,
5941 files_struct *fsp,
5942 struct smb_filename *smb_fname_src)
5944 bool overwrite;
5945 uint32 root_fid;
5946 uint32 len;
5947 char *newname = NULL;
5948 struct smb_filename *smb_fname_dst = NULL;
5949 bool dest_has_wcard = False;
5950 NTSTATUS status = NT_STATUS_OK;
5951 char *p;
5952 TALLOC_CTX *ctx = talloc_tos();
5954 if (total_data < 13) {
5955 return NT_STATUS_INVALID_PARAMETER;
5958 overwrite = (CVAL(pdata,0) ? True : False);
5959 root_fid = IVAL(pdata,4);
5960 len = IVAL(pdata,8);
5962 if (len > (total_data - 12) || (len == 0) || (root_fid != 0)) {
5963 return NT_STATUS_INVALID_PARAMETER;
5966 srvstr_get_path_wcard(ctx, pdata, req->flags2, &newname, &pdata[12],
5967 len, 0, &status,
5968 &dest_has_wcard);
5969 if (!NT_STATUS_IS_OK(status)) {
5970 return status;
5973 DEBUG(10,("smb_file_rename_information: got name |%s|\n",
5974 newname));
5976 status = resolve_dfspath_wcard(ctx, conn,
5977 req->flags2 & FLAGS2_DFS_PATHNAMES,
5978 newname,
5979 &newname,
5980 &dest_has_wcard);
5981 if (!NT_STATUS_IS_OK(status)) {
5982 return status;
5985 /* Check the new name has no '/' characters. */
5986 if (strchr_m(newname, '/')) {
5987 return NT_STATUS_NOT_SUPPORTED;
5990 if (fsp && fsp->base_fsp) {
5991 /* newname must be a stream name. */
5992 if (newname[0] != ':') {
5993 return NT_STATUS_NOT_SUPPORTED;
5996 /* Create an smb_fname to call rename_internals_fsp() with. */
5997 status = create_synthetic_smb_fname(talloc_tos(),
5998 fsp->base_fsp->fsp_name->base_name, newname, NULL,
5999 &smb_fname_dst);
6000 if (!NT_STATUS_IS_OK(status)) {
6001 goto out;
6005 * Set the original last component, since
6006 * rename_internals_fsp() requires it.
6008 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
6009 newname);
6010 if (smb_fname_dst->original_lcomp == NULL) {
6011 status = NT_STATUS_NO_MEMORY;
6012 goto out;
6015 } else {
6017 * Build up an smb_fname_dst based on the filename passed in.
6018 * We basically just strip off the last component, and put on
6019 * the newname instead.
6021 char *base_name = NULL;
6023 /* newname must *not* be a stream name. */
6024 if (newname[0] == ':') {
6025 return NT_STATUS_NOT_SUPPORTED;
6029 * Strip off the last component (filename) of the path passed
6030 * in.
6032 base_name = talloc_strdup(ctx, smb_fname_src->base_name);
6033 if (!base_name) {
6034 return NT_STATUS_NO_MEMORY;
6036 p = strrchr_m(base_name, '/');
6037 if (p) {
6038 p[1] = '\0';
6039 } else {
6040 base_name = talloc_strdup(ctx, "./");
6041 if (!base_name) {
6042 return NT_STATUS_NO_MEMORY;
6045 /* Append the new name. */
6046 base_name = talloc_asprintf_append(base_name,
6047 "%s",
6048 newname);
6049 if (!base_name) {
6050 return NT_STATUS_NO_MEMORY;
6053 status = unix_convert(ctx, conn, base_name, &smb_fname_dst,
6054 (UCF_SAVE_LCOMP |
6055 (dest_has_wcard ?
6056 UCF_ALWAYS_ALLOW_WCARD_LCOMP :
6057 0)));
6059 /* If an error we expect this to be
6060 * NT_STATUS_OBJECT_PATH_NOT_FOUND */
6062 if (!NT_STATUS_IS_OK(status)) {
6063 if(!NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
6064 status)) {
6065 goto out;
6067 /* Create an smb_fname to call rename_internals_fsp() */
6068 status = create_synthetic_smb_fname(ctx,
6069 base_name, NULL,
6070 NULL,
6071 &smb_fname_dst);
6072 if (!NT_STATUS_IS_OK(status)) {
6073 goto out;
6078 if (fsp) {
6079 DEBUG(10,("smb_file_rename_information: "
6080 "SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
6081 fsp->fnum, fsp_str_dbg(fsp),
6082 smb_fname_str_dbg(smb_fname_dst)));
6083 status = rename_internals_fsp(conn, fsp, smb_fname_dst, 0,
6084 overwrite);
6085 } else {
6086 DEBUG(10,("smb_file_rename_information: "
6087 "SMB_FILE_RENAME_INFORMATION %s -> %s\n",
6088 smb_fname_str_dbg(smb_fname_src),
6089 smb_fname_str_dbg(smb_fname_dst)));
6090 status = rename_internals(ctx, conn, req, smb_fname_src,
6091 smb_fname_dst, 0, overwrite, false,
6092 dest_has_wcard,
6093 FILE_WRITE_ATTRIBUTES);
6095 out:
6096 TALLOC_FREE(smb_fname_dst);
6097 return status;
6100 /****************************************************************************
6101 Deal with SMB_SET_POSIX_ACL.
6102 ****************************************************************************/
6104 #if defined(HAVE_POSIX_ACLS)
6105 static NTSTATUS smb_set_posix_acl(connection_struct *conn,
6106 const char *pdata,
6107 int total_data,
6108 files_struct *fsp,
6109 const struct smb_filename *smb_fname)
6111 uint16 posix_acl_version;
6112 uint16 num_file_acls;
6113 uint16 num_def_acls;
6114 bool valid_file_acls = True;
6115 bool valid_def_acls = True;
6117 if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
6118 return NT_STATUS_INVALID_PARAMETER;
6120 posix_acl_version = SVAL(pdata,0);
6121 num_file_acls = SVAL(pdata,2);
6122 num_def_acls = SVAL(pdata,4);
6124 if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
6125 valid_file_acls = False;
6126 num_file_acls = 0;
6129 if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
6130 valid_def_acls = False;
6131 num_def_acls = 0;
6134 if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
6135 return NT_STATUS_INVALID_PARAMETER;
6138 if (total_data < SMB_POSIX_ACL_HEADER_SIZE +
6139 (num_file_acls+num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE) {
6140 return NT_STATUS_INVALID_PARAMETER;
6143 DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
6144 smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
6145 (unsigned int)num_file_acls,
6146 (unsigned int)num_def_acls));
6148 if (valid_file_acls && !set_unix_posix_acl(conn, fsp,
6149 smb_fname->base_name, num_file_acls,
6150 pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
6151 return map_nt_error_from_unix(errno);
6154 if (valid_def_acls && !set_unix_posix_default_acl(conn,
6155 smb_fname->base_name, &smb_fname->st, num_def_acls,
6156 pdata + SMB_POSIX_ACL_HEADER_SIZE +
6157 (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) {
6158 return map_nt_error_from_unix(errno);
6160 return NT_STATUS_OK;
6162 #endif
6164 /****************************************************************************
6165 Deal with SMB_SET_POSIX_LOCK.
6166 ****************************************************************************/
6168 static NTSTATUS smb_set_posix_lock(connection_struct *conn,
6169 struct smb_request *req,
6170 const char *pdata,
6171 int total_data,
6172 files_struct *fsp)
6174 uint64_t count;
6175 uint64_t offset;
6176 uint32 lock_pid;
6177 bool blocking_lock = False;
6178 enum brl_type lock_type;
6180 NTSTATUS status = NT_STATUS_OK;
6182 if (fsp == NULL || fsp->fh->fd == -1) {
6183 return NT_STATUS_INVALID_HANDLE;
6186 if (total_data != POSIX_LOCK_DATA_SIZE) {
6187 return NT_STATUS_INVALID_PARAMETER;
6190 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
6191 case POSIX_LOCK_TYPE_READ:
6192 lock_type = READ_LOCK;
6193 break;
6194 case POSIX_LOCK_TYPE_WRITE:
6195 /* Return the right POSIX-mappable error code for files opened read-only. */
6196 if (!fsp->can_write) {
6197 return NT_STATUS_INVALID_HANDLE;
6199 lock_type = WRITE_LOCK;
6200 break;
6201 case POSIX_LOCK_TYPE_UNLOCK:
6202 lock_type = UNLOCK_LOCK;
6203 break;
6204 default:
6205 return NT_STATUS_INVALID_PARAMETER;
6208 if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
6209 blocking_lock = False;
6210 } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
6211 blocking_lock = True;
6212 } else {
6213 return NT_STATUS_INVALID_PARAMETER;
6216 if (!lp_blocking_locks(SNUM(conn))) {
6217 blocking_lock = False;
6220 lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
6221 #if defined(HAVE_LONGLONG)
6222 offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
6223 ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
6224 count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
6225 ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
6226 #else /* HAVE_LONGLONG */
6227 offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET);
6228 count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
6229 #endif /* HAVE_LONGLONG */
6231 DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u,"
6232 "lock_pid = %u, count = %.0f, offset = %.0f\n",
6233 fsp_str_dbg(fsp),
6234 (unsigned int)lock_type,
6235 (unsigned int)lock_pid,
6236 (double)count,
6237 (double)offset ));
6239 if (lock_type == UNLOCK_LOCK) {
6240 status = do_unlock(smbd_messaging_context(),
6241 fsp,
6242 lock_pid,
6243 count,
6244 offset,
6245 POSIX_LOCK);
6246 } else {
6247 uint32 block_smbpid;
6249 struct byte_range_lock *br_lck = do_lock(smbd_messaging_context(),
6250 fsp,
6251 lock_pid,
6252 count,
6253 offset,
6254 lock_type,
6255 POSIX_LOCK,
6256 blocking_lock,
6257 &status,
6258 &block_smbpid,
6259 NULL);
6261 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
6263 * A blocking lock was requested. Package up
6264 * this smb into a queued request and push it
6265 * onto the blocking lock queue.
6267 if(push_blocking_lock_request(br_lck,
6268 req,
6269 fsp,
6270 -1, /* infinite timeout. */
6272 lock_pid,
6273 lock_type,
6274 POSIX_LOCK,
6275 offset,
6276 count,
6277 block_smbpid)) {
6278 TALLOC_FREE(br_lck);
6279 return status;
6282 TALLOC_FREE(br_lck);
6285 return status;
6288 /****************************************************************************
6289 Deal with SMB_SET_FILE_BASIC_INFO.
6290 ****************************************************************************/
6292 static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
6293 const char *pdata,
6294 int total_data,
6295 files_struct *fsp,
6296 const struct smb_filename *smb_fname)
6298 /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
6299 struct smb_file_time ft;
6300 uint32 dosmode = 0;
6301 NTSTATUS status = NT_STATUS_OK;
6303 ZERO_STRUCT(ft);
6305 if (total_data < 36) {
6306 return NT_STATUS_INVALID_PARAMETER;
6309 /* Set the attributes */
6310 dosmode = IVAL(pdata,32);
6311 status = smb_set_file_dosmode(conn, smb_fname, dosmode);
6312 if (!NT_STATUS_IS_OK(status)) {
6313 return status;
6316 /* create time */
6317 ft.create_time = interpret_long_date(pdata);
6319 /* access time */
6320 ft.atime = interpret_long_date(pdata+8);
6322 /* write time. */
6323 ft.mtime = interpret_long_date(pdata+16);
6325 /* change time. */
6326 ft.ctime = interpret_long_date(pdata+24);
6328 DEBUG(10, ("smb_set_file_basic_info: file %s\n",
6329 smb_fname_str_dbg(smb_fname)));
6331 return smb_set_file_time(conn, fsp, smb_fname, &ft,
6332 true);
6335 /****************************************************************************
6336 Deal with SMB_INFO_STANDARD.
6337 ****************************************************************************/
6339 static NTSTATUS smb_set_info_standard(connection_struct *conn,
6340 const char *pdata,
6341 int total_data,
6342 files_struct *fsp,
6343 const struct smb_filename *smb_fname)
6345 struct smb_file_time ft;
6347 ZERO_STRUCT(ft);
6349 if (total_data < 12) {
6350 return NT_STATUS_INVALID_PARAMETER;
6353 /* create time */
6354 ft.create_time = convert_time_t_to_timespec(srv_make_unix_date2(pdata));
6355 /* access time */
6356 ft.atime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+4));
6357 /* write time */
6358 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+8));
6360 DEBUG(10,("smb_set_info_standard: file %s\n",
6361 smb_fname_str_dbg(smb_fname)));
6363 return smb_set_file_time(conn,
6364 fsp,
6365 smb_fname,
6366 &ft,
6367 true);
6370 /****************************************************************************
6371 Deal with SMB_SET_FILE_ALLOCATION_INFO.
6372 ****************************************************************************/
6374 static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
6375 struct smb_request *req,
6376 const char *pdata,
6377 int total_data,
6378 files_struct *fsp,
6379 struct smb_filename *smb_fname)
6381 uint64_t allocation_size = 0;
6382 NTSTATUS status = NT_STATUS_OK;
6383 files_struct *new_fsp = NULL;
6385 if (!VALID_STAT(smb_fname->st)) {
6386 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6389 if (total_data < 8) {
6390 return NT_STATUS_INVALID_PARAMETER;
6393 allocation_size = (uint64_t)IVAL(pdata,0);
6394 #ifdef LARGE_SMB_OFF_T
6395 allocation_size |= (((uint64_t)IVAL(pdata,4)) << 32);
6396 #else /* LARGE_SMB_OFF_T */
6397 if (IVAL(pdata,4) != 0) {
6398 /* more than 32 bits? */
6399 return NT_STATUS_INVALID_PARAMETER;
6401 #endif /* LARGE_SMB_OFF_T */
6403 DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for "
6404 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
6405 (double)allocation_size));
6407 if (allocation_size) {
6408 allocation_size = smb_roundup(conn, allocation_size);
6411 DEBUG(10,("smb_set_file_allocation_info: file %s : setting new "
6412 "allocation size to %.0f\n", smb_fname_str_dbg(smb_fname),
6413 (double)allocation_size));
6415 if (fsp && fsp->fh->fd != -1) {
6416 /* Open file handle. */
6417 /* Only change if needed. */
6418 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
6419 if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
6420 return map_nt_error_from_unix(errno);
6423 /* But always update the time. */
6425 * This is equivalent to a write. Ensure it's seen immediately
6426 * if there are no pending writes.
6428 trigger_write_time_update_immediate(fsp);
6429 return NT_STATUS_OK;
6432 /* Pathname or stat or directory file. */
6433 status = SMB_VFS_CREATE_FILE(
6434 conn, /* conn */
6435 req, /* req */
6436 0, /* root_dir_fid */
6437 smb_fname, /* fname */
6438 FILE_WRITE_DATA, /* access_mask */
6439 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6440 FILE_SHARE_DELETE),
6441 FILE_OPEN, /* create_disposition*/
6442 0, /* create_options */
6443 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6444 FORCE_OPLOCK_BREAK_TO_NONE, /* oplock_request */
6445 0, /* allocation_size */
6446 NULL, /* sd */
6447 NULL, /* ea_list */
6448 &new_fsp, /* result */
6449 NULL); /* pinfo */
6451 if (!NT_STATUS_IS_OK(status)) {
6452 /* NB. We check for open_was_deferred in the caller. */
6453 return status;
6456 /* Only change if needed. */
6457 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
6458 if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) {
6459 status = map_nt_error_from_unix(errno);
6460 close_file(req, new_fsp, NORMAL_CLOSE);
6461 return status;
6465 /* Changing the allocation size should set the last mod time. */
6467 * This is equivalent to a write. Ensure it's seen immediately
6468 * if there are no pending writes.
6470 trigger_write_time_update_immediate(new_fsp);
6472 close_file(req, new_fsp, NORMAL_CLOSE);
6473 return NT_STATUS_OK;
6476 /****************************************************************************
6477 Deal with SMB_SET_FILE_END_OF_FILE_INFO.
6478 ****************************************************************************/
6480 static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
6481 struct smb_request *req,
6482 const char *pdata,
6483 int total_data,
6484 files_struct *fsp,
6485 const struct smb_filename *smb_fname)
6487 SMB_OFF_T size;
6489 if (total_data < 8) {
6490 return NT_STATUS_INVALID_PARAMETER;
6493 size = IVAL(pdata,0);
6494 #ifdef LARGE_SMB_OFF_T
6495 size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
6496 #else /* LARGE_SMB_OFF_T */
6497 if (IVAL(pdata,4) != 0) {
6498 /* more than 32 bits? */
6499 return NT_STATUS_INVALID_PARAMETER;
6501 #endif /* LARGE_SMB_OFF_T */
6502 DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for "
6503 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
6504 (double)size));
6506 return smb_set_file_size(conn, req,
6507 fsp,
6508 smb_fname,
6509 &smb_fname->st,
6510 size);
6513 /****************************************************************************
6514 Allow a UNIX info mknod.
6515 ****************************************************************************/
6517 static NTSTATUS smb_unix_mknod(connection_struct *conn,
6518 const char *pdata,
6519 int total_data,
6520 const struct smb_filename *smb_fname)
6522 uint32 file_type = IVAL(pdata,56);
6523 #if defined(HAVE_MAKEDEV)
6524 uint32 dev_major = IVAL(pdata,60);
6525 uint32 dev_minor = IVAL(pdata,68);
6526 #endif
6527 SMB_DEV_T dev = (SMB_DEV_T)0;
6528 uint32 raw_unixmode = IVAL(pdata,84);
6529 NTSTATUS status;
6530 mode_t unixmode;
6532 if (total_data < 100) {
6533 return NT_STATUS_INVALID_PARAMETER;
6536 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6537 PERM_NEW_FILE, &unixmode);
6538 if (!NT_STATUS_IS_OK(status)) {
6539 return status;
6542 #if defined(HAVE_MAKEDEV)
6543 dev = makedev(dev_major, dev_minor);
6544 #endif
6546 switch (file_type) {
6547 #if defined(S_IFIFO)
6548 case UNIX_TYPE_FIFO:
6549 unixmode |= S_IFIFO;
6550 break;
6551 #endif
6552 #if defined(S_IFSOCK)
6553 case UNIX_TYPE_SOCKET:
6554 unixmode |= S_IFSOCK;
6555 break;
6556 #endif
6557 #if defined(S_IFCHR)
6558 case UNIX_TYPE_CHARDEV:
6559 unixmode |= S_IFCHR;
6560 break;
6561 #endif
6562 #if defined(S_IFBLK)
6563 case UNIX_TYPE_BLKDEV:
6564 unixmode |= S_IFBLK;
6565 break;
6566 #endif
6567 default:
6568 return NT_STATUS_INVALID_PARAMETER;
6571 DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
6572 "%.0f mode 0%o for file %s\n", (double)dev,
6573 (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
6575 /* Ok - do the mknod. */
6576 if (SMB_VFS_MKNOD(conn, smb_fname->base_name, unixmode, dev) != 0) {
6577 return map_nt_error_from_unix(errno);
6580 /* If any of the other "set" calls fail we
6581 * don't want to end up with a half-constructed mknod.
6584 if (lp_inherit_perms(SNUM(conn))) {
6585 char *parent;
6586 if (!parent_dirname(talloc_tos(), smb_fname->base_name,
6587 &parent, NULL)) {
6588 return NT_STATUS_NO_MEMORY;
6590 inherit_access_posix_acl(conn, parent, smb_fname->base_name,
6591 unixmode);
6592 TALLOC_FREE(parent);
6595 return NT_STATUS_OK;
6598 /****************************************************************************
6599 Deal with SMB_SET_FILE_UNIX_BASIC.
6600 ****************************************************************************/
6602 static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
6603 struct smb_request *req,
6604 const char *pdata,
6605 int total_data,
6606 files_struct *fsp,
6607 const struct smb_filename *smb_fname)
6609 struct smb_file_time ft;
6610 uint32 raw_unixmode;
6611 mode_t unixmode;
6612 SMB_OFF_T size = 0;
6613 uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
6614 gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
6615 NTSTATUS status = NT_STATUS_OK;
6616 bool delete_on_fail = False;
6617 enum perm_type ptype;
6618 files_struct *all_fsps = NULL;
6619 bool modify_mtime = true;
6620 struct file_id id;
6621 SMB_STRUCT_STAT sbuf;
6623 ZERO_STRUCT(ft);
6625 if (total_data < 100) {
6626 return NT_STATUS_INVALID_PARAMETER;
6629 if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
6630 IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
6631 size=IVAL(pdata,0); /* first 8 Bytes are size */
6632 #ifdef LARGE_SMB_OFF_T
6633 size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
6634 #else /* LARGE_SMB_OFF_T */
6635 if (IVAL(pdata,4) != 0) {
6636 /* more than 32 bits? */
6637 return NT_STATUS_INVALID_PARAMETER;
6639 #endif /* LARGE_SMB_OFF_T */
6642 ft.atime = interpret_long_date(pdata+24); /* access_time */
6643 ft.mtime = interpret_long_date(pdata+32); /* modification_time */
6644 set_owner = (uid_t)IVAL(pdata,40);
6645 set_grp = (gid_t)IVAL(pdata,48);
6646 raw_unixmode = IVAL(pdata,84);
6648 if (VALID_STAT(smb_fname->st)) {
6649 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
6650 ptype = PERM_EXISTING_DIR;
6651 } else {
6652 ptype = PERM_EXISTING_FILE;
6654 } else {
6655 ptype = PERM_NEW_FILE;
6658 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6659 ptype, &unixmode);
6660 if (!NT_STATUS_IS_OK(status)) {
6661 return status;
6664 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
6665 "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
6666 smb_fname_str_dbg(smb_fname), (double)size,
6667 (unsigned int)set_owner, (unsigned int)set_grp,
6668 (int)raw_unixmode));
6670 sbuf = smb_fname->st;
6672 if (!VALID_STAT(sbuf)) {
6673 struct smb_filename *smb_fname_tmp = NULL;
6675 * The only valid use of this is to create character and block
6676 * devices, and named pipes. This is deprecated (IMHO) and
6677 * a new info level should be used for mknod. JRA.
6680 status = smb_unix_mknod(conn,
6681 pdata,
6682 total_data,
6683 smb_fname);
6684 if (!NT_STATUS_IS_OK(status)) {
6685 return status;
6688 status = copy_smb_filename(talloc_tos(), smb_fname,
6689 &smb_fname_tmp);
6690 if (!NT_STATUS_IS_OK(status)) {
6691 return status;
6694 if (SMB_VFS_STAT(conn, smb_fname_tmp) != 0) {
6695 status = map_nt_error_from_unix(errno);
6696 TALLOC_FREE(smb_fname_tmp);
6697 SMB_VFS_UNLINK(conn, smb_fname);
6698 return status;
6701 sbuf = smb_fname_tmp->st;
6702 TALLOC_FREE(smb_fname_tmp);
6704 /* Ensure we don't try and change anything else. */
6705 raw_unixmode = SMB_MODE_NO_CHANGE;
6706 size = get_file_size_stat(&sbuf);
6707 ft.atime = sbuf.st_ex_atime;
6708 ft.mtime = sbuf.st_ex_mtime;
6710 * We continue here as we might want to change the
6711 * owner uid/gid.
6713 delete_on_fail = True;
6716 #if 1
6717 /* Horrible backwards compatibility hack as an old server bug
6718 * allowed a CIFS client bug to remain unnoticed :-(. JRA.
6719 * */
6721 if (!size) {
6722 size = get_file_size_stat(&sbuf);
6724 #endif
6727 * Deal with the UNIX specific mode set.
6730 if (raw_unixmode != SMB_MODE_NO_CHANGE) {
6731 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6732 "setting mode 0%o for file %s\n",
6733 (unsigned int)unixmode,
6734 smb_fname_str_dbg(smb_fname)));
6735 if (SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode) != 0) {
6736 return map_nt_error_from_unix(errno);
6741 * Deal with the UNIX specific uid set.
6744 if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
6745 (sbuf.st_ex_uid != set_owner)) {
6746 int ret;
6748 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6749 "changing owner %u for path %s\n",
6750 (unsigned int)set_owner,
6751 smb_fname_str_dbg(smb_fname)));
6753 if (S_ISLNK(sbuf.st_ex_mode)) {
6754 ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name,
6755 set_owner, (gid_t)-1);
6756 } else {
6757 ret = SMB_VFS_CHOWN(conn, smb_fname->base_name,
6758 set_owner, (gid_t)-1);
6761 if (ret != 0) {
6762 status = map_nt_error_from_unix(errno);
6763 if (delete_on_fail) {
6764 SMB_VFS_UNLINK(conn, smb_fname);
6766 return status;
6771 * Deal with the UNIX specific gid set.
6774 if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
6775 (sbuf.st_ex_gid != set_grp)) {
6776 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6777 "changing group %u for file %s\n",
6778 (unsigned int)set_owner,
6779 smb_fname_str_dbg(smb_fname)));
6780 if (SMB_VFS_CHOWN(conn, smb_fname->base_name, (uid_t)-1,
6781 set_grp) != 0) {
6782 status = map_nt_error_from_unix(errno);
6783 if (delete_on_fail) {
6784 SMB_VFS_UNLINK(conn, smb_fname);
6786 return status;
6790 /* Deal with any size changes. */
6792 status = smb_set_file_size(conn, req,
6793 fsp,
6794 smb_fname,
6795 &sbuf,
6796 size);
6797 if (!NT_STATUS_IS_OK(status)) {
6798 return status;
6801 /* Deal with any time changes. */
6802 if (null_timespec(ft.mtime) && null_timespec(ft.atime)) {
6803 /* No change, don't cancel anything. */
6804 return status;
6807 id = vfs_file_id_from_sbuf(conn, &sbuf);
6808 for(all_fsps = file_find_di_first(id); all_fsps;
6809 all_fsps = file_find_di_next(all_fsps)) {
6811 * We're setting the time explicitly for UNIX.
6812 * Cancel any pending changes over all handles.
6814 all_fsps->update_write_time_on_close = false;
6815 TALLOC_FREE(all_fsps->update_write_time_event);
6819 * Override the "setting_write_time"
6820 * parameter here as it almost does what
6821 * we need. Just remember if we modified
6822 * mtime and send the notify ourselves.
6824 if (null_timespec(ft.mtime)) {
6825 modify_mtime = false;
6828 status = smb_set_file_time(conn,
6829 fsp,
6830 smb_fname,
6831 &ft,
6832 false);
6833 if (modify_mtime) {
6834 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6835 FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
6837 return status;
6840 /****************************************************************************
6841 Deal with SMB_SET_FILE_UNIX_INFO2.
6842 ****************************************************************************/
6844 static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
6845 struct smb_request *req,
6846 const char *pdata,
6847 int total_data,
6848 files_struct *fsp,
6849 const struct smb_filename *smb_fname)
6851 NTSTATUS status;
6852 uint32 smb_fflags;
6853 uint32 smb_fmask;
6855 if (total_data < 116) {
6856 return NT_STATUS_INVALID_PARAMETER;
6859 /* Start by setting all the fields that are common between UNIX_BASIC
6860 * and UNIX_INFO2.
6862 status = smb_set_file_unix_basic(conn, req, pdata, total_data,
6863 fsp, smb_fname);
6864 if (!NT_STATUS_IS_OK(status)) {
6865 return status;
6868 smb_fflags = IVAL(pdata, 108);
6869 smb_fmask = IVAL(pdata, 112);
6871 /* NB: We should only attempt to alter the file flags if the client
6872 * sends a non-zero mask.
6874 if (smb_fmask != 0) {
6875 int stat_fflags = 0;
6877 if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
6878 smb_fmask, &stat_fflags)) {
6879 /* Client asked to alter a flag we don't understand. */
6880 return NT_STATUS_INVALID_PARAMETER;
6883 if (fsp && fsp->fh->fd != -1) {
6884 /* XXX: we should be using SMB_VFS_FCHFLAGS here. */
6885 return NT_STATUS_NOT_SUPPORTED;
6886 } else {
6887 if (SMB_VFS_CHFLAGS(conn, smb_fname->base_name,
6888 stat_fflags) != 0) {
6889 return map_nt_error_from_unix(errno);
6894 /* XXX: need to add support for changing the create_time here. You
6895 * can do this for paths on Darwin with setattrlist(2). The right way
6896 * to hook this up is probably by extending the VFS utimes interface.
6899 return NT_STATUS_OK;
6902 /****************************************************************************
6903 Create a directory with POSIX semantics.
6904 ****************************************************************************/
6906 static NTSTATUS smb_posix_mkdir(connection_struct *conn,
6907 struct smb_request *req,
6908 char **ppdata,
6909 int total_data,
6910 struct smb_filename *smb_fname,
6911 int *pdata_return_size)
6913 NTSTATUS status = NT_STATUS_OK;
6914 uint32 raw_unixmode = 0;
6915 uint32 mod_unixmode = 0;
6916 mode_t unixmode = (mode_t)0;
6917 files_struct *fsp = NULL;
6918 uint16 info_level_return = 0;
6919 int info;
6920 char *pdata = *ppdata;
6922 if (total_data < 18) {
6923 return NT_STATUS_INVALID_PARAMETER;
6926 raw_unixmode = IVAL(pdata,8);
6927 /* Next 4 bytes are not yet defined. */
6929 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6930 PERM_NEW_DIR, &unixmode);
6931 if (!NT_STATUS_IS_OK(status)) {
6932 return status;
6935 mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
6937 DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
6938 smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
6940 status = SMB_VFS_CREATE_FILE(
6941 conn, /* conn */
6942 req, /* req */
6943 0, /* root_dir_fid */
6944 smb_fname, /* fname */
6945 FILE_READ_ATTRIBUTES, /* access_mask */
6946 FILE_SHARE_NONE, /* share_access */
6947 FILE_CREATE, /* create_disposition*/
6948 FILE_DIRECTORY_FILE, /* create_options */
6949 mod_unixmode, /* file_attributes */
6950 0, /* oplock_request */
6951 0, /* allocation_size */
6952 NULL, /* sd */
6953 NULL, /* ea_list */
6954 &fsp, /* result */
6955 &info); /* pinfo */
6957 if (NT_STATUS_IS_OK(status)) {
6958 close_file(req, fsp, NORMAL_CLOSE);
6961 info_level_return = SVAL(pdata,16);
6963 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
6964 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
6965 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
6966 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
6967 } else {
6968 *pdata_return_size = 12;
6971 /* Realloc the data size */
6972 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
6973 if (*ppdata == NULL) {
6974 *pdata_return_size = 0;
6975 return NT_STATUS_NO_MEMORY;
6977 pdata = *ppdata;
6979 SSVAL(pdata,0,NO_OPLOCK_RETURN);
6980 SSVAL(pdata,2,0); /* No fnum. */
6981 SIVAL(pdata,4,info); /* Was directory created. */
6983 switch (info_level_return) {
6984 case SMB_QUERY_FILE_UNIX_BASIC:
6985 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
6986 SSVAL(pdata,10,0); /* Padding. */
6987 store_file_unix_basic(conn, pdata + 12, fsp,
6988 &smb_fname->st);
6989 break;
6990 case SMB_QUERY_FILE_UNIX_INFO2:
6991 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
6992 SSVAL(pdata,10,0); /* Padding. */
6993 store_file_unix_basic_info2(conn, pdata + 12, fsp,
6994 &smb_fname->st);
6995 break;
6996 default:
6997 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
6998 SSVAL(pdata,10,0); /* Padding. */
6999 break;
7002 return status;
7005 /****************************************************************************
7006 Open/Create a file with POSIX semantics.
7007 ****************************************************************************/
7009 static NTSTATUS smb_posix_open(connection_struct *conn,
7010 struct smb_request *req,
7011 char **ppdata,
7012 int total_data,
7013 struct smb_filename *smb_fname,
7014 int *pdata_return_size)
7016 bool extended_oplock_granted = False;
7017 char *pdata = *ppdata;
7018 uint32 flags = 0;
7019 uint32 wire_open_mode = 0;
7020 uint32 raw_unixmode = 0;
7021 uint32 mod_unixmode = 0;
7022 uint32 create_disp = 0;
7023 uint32 access_mask = 0;
7024 uint32 create_options = 0;
7025 NTSTATUS status = NT_STATUS_OK;
7026 mode_t unixmode = (mode_t)0;
7027 files_struct *fsp = NULL;
7028 int oplock_request = 0;
7029 int info = 0;
7030 uint16 info_level_return = 0;
7032 if (total_data < 18) {
7033 return NT_STATUS_INVALID_PARAMETER;
7036 flags = IVAL(pdata,0);
7037 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
7038 if (oplock_request) {
7039 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
7042 wire_open_mode = IVAL(pdata,4);
7044 if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
7045 return smb_posix_mkdir(conn, req,
7046 ppdata,
7047 total_data,
7048 smb_fname,
7049 pdata_return_size);
7052 switch (wire_open_mode & SMB_ACCMODE) {
7053 case SMB_O_RDONLY:
7054 access_mask = FILE_READ_DATA;
7055 break;
7056 case SMB_O_WRONLY:
7057 access_mask = FILE_WRITE_DATA;
7058 break;
7059 case SMB_O_RDWR:
7060 access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
7061 break;
7062 default:
7063 DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
7064 (unsigned int)wire_open_mode ));
7065 return NT_STATUS_INVALID_PARAMETER;
7068 wire_open_mode &= ~SMB_ACCMODE;
7070 if((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) == (SMB_O_CREAT | SMB_O_EXCL)) {
7071 create_disp = FILE_CREATE;
7072 } else if((wire_open_mode & (SMB_O_CREAT | SMB_O_TRUNC)) == (SMB_O_CREAT | SMB_O_TRUNC)) {
7073 create_disp = FILE_OVERWRITE_IF;
7074 } else if((wire_open_mode & SMB_O_CREAT) == SMB_O_CREAT) {
7075 create_disp = FILE_OPEN_IF;
7076 } else if ((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL | SMB_O_TRUNC)) == 0) {
7077 create_disp = FILE_OPEN;
7078 } else {
7079 DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
7080 (unsigned int)wire_open_mode ));
7081 return NT_STATUS_INVALID_PARAMETER;
7084 raw_unixmode = IVAL(pdata,8);
7085 /* Next 4 bytes are not yet defined. */
7087 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
7088 (VALID_STAT(smb_fname->st) ?
7089 PERM_EXISTING_FILE : PERM_NEW_FILE),
7090 &unixmode);
7092 if (!NT_STATUS_IS_OK(status)) {
7093 return status;
7096 mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
7098 if (wire_open_mode & SMB_O_SYNC) {
7099 create_options |= FILE_WRITE_THROUGH;
7101 if (wire_open_mode & SMB_O_APPEND) {
7102 access_mask |= FILE_APPEND_DATA;
7104 if (wire_open_mode & SMB_O_DIRECT) {
7105 mod_unixmode |= FILE_FLAG_NO_BUFFERING;
7108 DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
7109 smb_fname_str_dbg(smb_fname),
7110 (unsigned int)wire_open_mode,
7111 (unsigned int)unixmode ));
7113 status = SMB_VFS_CREATE_FILE(
7114 conn, /* conn */
7115 req, /* req */
7116 0, /* root_dir_fid */
7117 smb_fname, /* fname */
7118 access_mask, /* access_mask */
7119 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7120 FILE_SHARE_DELETE),
7121 create_disp, /* create_disposition*/
7122 FILE_NON_DIRECTORY_FILE, /* create_options */
7123 mod_unixmode, /* file_attributes */
7124 oplock_request, /* oplock_request */
7125 0, /* allocation_size */
7126 NULL, /* sd */
7127 NULL, /* ea_list */
7128 &fsp, /* result */
7129 &info); /* pinfo */
7131 if (!NT_STATUS_IS_OK(status)) {
7132 return status;
7135 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
7136 extended_oplock_granted = True;
7139 if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
7140 extended_oplock_granted = True;
7143 info_level_return = SVAL(pdata,16);
7145 /* Allocate the correct return size. */
7147 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
7148 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
7149 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
7150 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
7151 } else {
7152 *pdata_return_size = 12;
7155 /* Realloc the data size */
7156 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
7157 if (*ppdata == NULL) {
7158 close_file(req, fsp, ERROR_CLOSE);
7159 *pdata_return_size = 0;
7160 return NT_STATUS_NO_MEMORY;
7162 pdata = *ppdata;
7164 if (extended_oplock_granted) {
7165 if (flags & REQUEST_BATCH_OPLOCK) {
7166 SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
7167 } else {
7168 SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
7170 } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
7171 SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
7172 } else {
7173 SSVAL(pdata,0,NO_OPLOCK_RETURN);
7176 SSVAL(pdata,2,fsp->fnum);
7177 SIVAL(pdata,4,info); /* Was file created etc. */
7179 switch (info_level_return) {
7180 case SMB_QUERY_FILE_UNIX_BASIC:
7181 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
7182 SSVAL(pdata,10,0); /* padding. */
7183 store_file_unix_basic(conn, pdata + 12, fsp,
7184 &smb_fname->st);
7185 break;
7186 case SMB_QUERY_FILE_UNIX_INFO2:
7187 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
7188 SSVAL(pdata,10,0); /* padding. */
7189 store_file_unix_basic_info2(conn, pdata + 12, fsp,
7190 &smb_fname->st);
7191 break;
7192 default:
7193 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
7194 SSVAL(pdata,10,0); /* padding. */
7195 break;
7197 return NT_STATUS_OK;
7200 /****************************************************************************
7201 Delete a file with POSIX semantics.
7202 ****************************************************************************/
7204 static NTSTATUS smb_posix_unlink(connection_struct *conn,
7205 struct smb_request *req,
7206 const char *pdata,
7207 int total_data,
7208 struct smb_filename *smb_fname)
7210 NTSTATUS status = NT_STATUS_OK;
7211 files_struct *fsp = NULL;
7212 uint16 flags = 0;
7213 char del = 1;
7214 int info = 0;
7215 int create_options = 0;
7216 int i;
7217 struct share_mode_lock *lck = NULL;
7219 if (total_data < 2) {
7220 return NT_STATUS_INVALID_PARAMETER;
7223 flags = SVAL(pdata,0);
7225 if (!VALID_STAT(smb_fname->st)) {
7226 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
7229 if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
7230 !VALID_STAT_OF_DIR(smb_fname->st)) {
7231 return NT_STATUS_NOT_A_DIRECTORY;
7234 DEBUG(10,("smb_posix_unlink: %s %s\n",
7235 (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
7236 smb_fname_str_dbg(smb_fname)));
7238 if (VALID_STAT_OF_DIR(smb_fname->st)) {
7239 create_options |= FILE_DIRECTORY_FILE;
7242 status = SMB_VFS_CREATE_FILE(
7243 conn, /* conn */
7244 req, /* req */
7245 0, /* root_dir_fid */
7246 smb_fname, /* fname */
7247 DELETE_ACCESS, /* access_mask */
7248 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7249 FILE_SHARE_DELETE),
7250 FILE_OPEN, /* create_disposition*/
7251 create_options, /* create_options */
7252 FILE_FLAG_POSIX_SEMANTICS|0777, /* file_attributes */
7253 0, /* oplock_request */
7254 0, /* allocation_size */
7255 NULL, /* sd */
7256 NULL, /* ea_list */
7257 &fsp, /* result */
7258 &info); /* pinfo */
7260 if (!NT_STATUS_IS_OK(status)) {
7261 return status;
7265 * Don't lie to client. If we can't really delete due to
7266 * non-POSIX opens return SHARING_VIOLATION.
7269 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
7270 NULL);
7271 if (lck == NULL) {
7272 DEBUG(0, ("smb_posix_unlink: Could not get share mode "
7273 "lock for file %s\n", fsp_str_dbg(fsp)));
7274 close_file(req, fsp, NORMAL_CLOSE);
7275 return NT_STATUS_INVALID_PARAMETER;
7279 * See if others still have the file open. If this is the case, then
7280 * don't delete. If all opens are POSIX delete we can set the delete
7281 * on close disposition.
7283 for (i=0; i<lck->num_share_modes; i++) {
7284 struct share_mode_entry *e = &lck->share_modes[i];
7285 if (is_valid_share_mode_entry(e)) {
7286 if (e->flags & SHARE_MODE_FLAG_POSIX_OPEN) {
7287 continue;
7289 /* Fail with sharing violation. */
7290 close_file(req, fsp, NORMAL_CLOSE);
7291 TALLOC_FREE(lck);
7292 return NT_STATUS_SHARING_VIOLATION;
7297 * Set the delete on close.
7299 status = smb_set_file_disposition_info(conn,
7300 &del,
7302 fsp,
7303 smb_fname);
7305 if (!NT_STATUS_IS_OK(status)) {
7306 close_file(req, fsp, NORMAL_CLOSE);
7307 TALLOC_FREE(lck);
7308 return status;
7310 TALLOC_FREE(lck);
7311 return close_file(req, fsp, NORMAL_CLOSE);
7314 NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
7315 struct smb_request *req,
7316 TALLOC_CTX *mem_ctx,
7317 uint16_t info_level,
7318 files_struct *fsp,
7319 struct smb_filename *smb_fname,
7320 char **ppdata, int total_data,
7321 int *ret_data_size)
7323 char *pdata = *ppdata;
7324 NTSTATUS status = NT_STATUS_OK;
7325 int data_return_size = 0;
7327 *ret_data_size = 0;
7329 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
7330 return NT_STATUS_INVALID_LEVEL;
7333 if (!CAN_WRITE(conn)) {
7334 /* Allow POSIX opens. The open path will deny
7335 * any non-readonly opens. */
7336 if (info_level != SMB_POSIX_PATH_OPEN) {
7337 return NT_STATUS_DOS(ERRSRV, ERRaccess);
7341 DEBUG(3,("smbd_do_setfilepathinfo: %s (fnum %d) info_level=%d "
7342 "totdata=%d\n", smb_fname_str_dbg(smb_fname),
7343 fsp ? fsp->fnum : -1, info_level, total_data));
7345 switch (info_level) {
7347 case SMB_INFO_STANDARD:
7349 status = smb_set_info_standard(conn,
7350 pdata,
7351 total_data,
7352 fsp,
7353 smb_fname);
7354 break;
7357 case SMB_INFO_SET_EA:
7359 status = smb_info_set_ea(conn,
7360 pdata,
7361 total_data,
7362 fsp,
7363 smb_fname);
7364 break;
7367 case SMB_SET_FILE_BASIC_INFO:
7368 case SMB_FILE_BASIC_INFORMATION:
7370 status = smb_set_file_basic_info(conn,
7371 pdata,
7372 total_data,
7373 fsp,
7374 smb_fname);
7375 break;
7378 case SMB_FILE_ALLOCATION_INFORMATION:
7379 case SMB_SET_FILE_ALLOCATION_INFO:
7381 status = smb_set_file_allocation_info(conn, req,
7382 pdata,
7383 total_data,
7384 fsp,
7385 smb_fname);
7386 break;
7389 case SMB_FILE_END_OF_FILE_INFORMATION:
7390 case SMB_SET_FILE_END_OF_FILE_INFO:
7392 status = smb_set_file_end_of_file_info(conn, req,
7393 pdata,
7394 total_data,
7395 fsp,
7396 smb_fname);
7397 break;
7400 case SMB_FILE_DISPOSITION_INFORMATION:
7401 case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
7403 #if 0
7404 /* JRA - We used to just ignore this on a path ?
7405 * Shouldn't this be invalid level on a pathname
7406 * based call ?
7408 if (tran_call != TRANSACT2_SETFILEINFO) {
7409 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
7411 #endif
7412 status = smb_set_file_disposition_info(conn,
7413 pdata,
7414 total_data,
7415 fsp,
7416 smb_fname);
7417 break;
7420 case SMB_FILE_POSITION_INFORMATION:
7422 status = smb_file_position_information(conn,
7423 pdata,
7424 total_data,
7425 fsp);
7426 break;
7429 case SMB_FILE_FULL_EA_INFORMATION:
7431 status = smb_set_file_full_ea_info(conn,
7432 pdata,
7433 total_data,
7434 fsp);
7435 break;
7438 /* From tridge Samba4 :
7439 * MODE_INFORMATION in setfileinfo (I have no
7440 * idea what "mode information" on a file is - it takes a value of 0,
7441 * 2, 4 or 6. What could it be?).
7444 case SMB_FILE_MODE_INFORMATION:
7446 status = smb_file_mode_information(conn,
7447 pdata,
7448 total_data);
7449 break;
7453 * CIFS UNIX extensions.
7456 case SMB_SET_FILE_UNIX_BASIC:
7458 status = smb_set_file_unix_basic(conn, req,
7459 pdata,
7460 total_data,
7461 fsp,
7462 smb_fname);
7463 break;
7466 case SMB_SET_FILE_UNIX_INFO2:
7468 status = smb_set_file_unix_info2(conn, req,
7469 pdata,
7470 total_data,
7471 fsp,
7472 smb_fname);
7473 break;
7476 case SMB_SET_FILE_UNIX_LINK:
7478 if (fsp) {
7479 /* We must have a pathname for this. */
7480 return NT_STATUS_INVALID_LEVEL;
7482 status = smb_set_file_unix_link(conn, req, pdata,
7483 total_data, smb_fname);
7484 break;
7487 case SMB_SET_FILE_UNIX_HLINK:
7489 if (fsp) {
7490 /* We must have a pathname for this. */
7491 return NT_STATUS_INVALID_LEVEL;
7493 status = smb_set_file_unix_hlink(conn, req,
7494 pdata, total_data,
7495 smb_fname);
7496 break;
7499 case SMB_FILE_RENAME_INFORMATION:
7501 status = smb_file_rename_information(conn, req,
7502 pdata, total_data,
7503 fsp, smb_fname);
7504 break;
7507 #if defined(HAVE_POSIX_ACLS)
7508 case SMB_SET_POSIX_ACL:
7510 status = smb_set_posix_acl(conn,
7511 pdata,
7512 total_data,
7513 fsp,
7514 smb_fname);
7515 break;
7517 #endif
7519 case SMB_SET_POSIX_LOCK:
7521 if (!fsp) {
7522 return NT_STATUS_INVALID_LEVEL;
7524 status = smb_set_posix_lock(conn, req,
7525 pdata, total_data, fsp);
7526 break;
7529 case SMB_POSIX_PATH_OPEN:
7531 if (fsp) {
7532 /* We must have a pathname for this. */
7533 return NT_STATUS_INVALID_LEVEL;
7536 status = smb_posix_open(conn, req,
7537 ppdata,
7538 total_data,
7539 smb_fname,
7540 &data_return_size);
7541 break;
7544 case SMB_POSIX_PATH_UNLINK:
7546 if (fsp) {
7547 /* We must have a pathname for this. */
7548 return NT_STATUS_INVALID_LEVEL;
7551 status = smb_posix_unlink(conn, req,
7552 pdata,
7553 total_data,
7554 smb_fname);
7555 break;
7558 default:
7559 return NT_STATUS_INVALID_LEVEL;
7562 if (!NT_STATUS_IS_OK(status)) {
7563 return status;
7566 *ret_data_size = data_return_size;
7567 return NT_STATUS_OK;
7570 /****************************************************************************
7571 Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname).
7572 ****************************************************************************/
7574 static void call_trans2setfilepathinfo(connection_struct *conn,
7575 struct smb_request *req,
7576 unsigned int tran_call,
7577 char **pparams, int total_params,
7578 char **ppdata, int total_data,
7579 unsigned int max_data_bytes)
7581 char *params = *pparams;
7582 char *pdata = *ppdata;
7583 uint16 info_level;
7584 struct smb_filename *smb_fname = NULL;
7585 files_struct *fsp = NULL;
7586 NTSTATUS status = NT_STATUS_OK;
7587 int data_return_size = 0;
7589 if (!params) {
7590 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7591 return;
7594 if (tran_call == TRANSACT2_SETFILEINFO) {
7595 if (total_params < 4) {
7596 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7597 return;
7600 fsp = file_fsp(req, SVAL(params,0));
7601 /* Basic check for non-null fsp. */
7602 if (!check_fsp_open(conn, req, fsp)) {
7603 return;
7605 info_level = SVAL(params,2);
7607 status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
7608 &smb_fname);
7609 if (!NT_STATUS_IS_OK(status)) {
7610 reply_nterror(req, status);
7611 return;
7614 if(fsp->is_directory || fsp->fh->fd == -1) {
7616 * This is actually a SETFILEINFO on a directory
7617 * handle (returned from an NT SMB). NT5.0 seems
7618 * to do this call. JRA.
7620 if (INFO_LEVEL_IS_UNIX(info_level)) {
7621 /* Always do lstat for UNIX calls. */
7622 if (SMB_VFS_LSTAT(conn, smb_fname)) {
7623 DEBUG(3,("call_trans2setfilepathinfo: "
7624 "SMB_VFS_LSTAT of %s failed "
7625 "(%s)\n",
7626 smb_fname_str_dbg(smb_fname),
7627 strerror(errno)));
7628 reply_nterror(req, map_nt_error_from_unix(errno));
7629 return;
7631 } else {
7632 if (SMB_VFS_STAT(conn, smb_fname) != 0) {
7633 DEBUG(3,("call_trans2setfilepathinfo: "
7634 "fileinfo of %s failed (%s)\n",
7635 smb_fname_str_dbg(smb_fname),
7636 strerror(errno)));
7637 reply_nterror(req, map_nt_error_from_unix(errno));
7638 return;
7641 } else if (fsp->print_file) {
7643 * Doing a DELETE_ON_CLOSE should cancel a print job.
7645 if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
7646 fsp->fh->private_options |= FILE_DELETE_ON_CLOSE;
7648 DEBUG(3,("call_trans2setfilepathinfo: "
7649 "Cancelling print job (%s)\n",
7650 fsp_str_dbg(fsp)));
7652 SSVAL(params,0,0);
7653 send_trans2_replies(conn, req, params, 2,
7654 *ppdata, 0,
7655 max_data_bytes);
7656 return;
7657 } else {
7658 reply_doserror(req, ERRDOS, ERRbadpath);
7659 return;
7661 } else {
7663 * Original code - this is an open file.
7665 if (!check_fsp(conn, req, fsp)) {
7666 return;
7669 if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
7670 DEBUG(3,("call_trans2setfilepathinfo: fstat "
7671 "of fnum %d failed (%s)\n", fsp->fnum,
7672 strerror(errno)));
7673 reply_nterror(req, map_nt_error_from_unix(errno));
7674 return;
7677 } else {
7678 char *fname = NULL;
7680 /* set path info */
7681 if (total_params < 7) {
7682 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7683 return;
7686 info_level = SVAL(params,0);
7687 srvstr_get_path(req, params, req->flags2, &fname, &params[6],
7688 total_params - 6, STR_TERMINATE,
7689 &status);
7690 if (!NT_STATUS_IS_OK(status)) {
7691 reply_nterror(req, status);
7692 return;
7695 status = filename_convert(req, conn,
7696 req->flags2 & FLAGS2_DFS_PATHNAMES,
7697 fname,
7699 NULL,
7700 &smb_fname);
7701 if (!NT_STATUS_IS_OK(status)) {
7702 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7703 reply_botherror(req,
7704 NT_STATUS_PATH_NOT_COVERED,
7705 ERRSRV, ERRbadpath);
7706 return;
7708 reply_nterror(req, status);
7709 return;
7712 if (INFO_LEVEL_IS_UNIX(info_level)) {
7714 * For CIFS UNIX extensions the target name may not exist.
7717 /* Always do lstat for UNIX calls. */
7718 SMB_VFS_LSTAT(conn, smb_fname);
7720 } else if (!VALID_STAT(smb_fname->st) &&
7721 SMB_VFS_STAT(conn, smb_fname)) {
7722 DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of "
7723 "%s failed (%s)\n",
7724 smb_fname_str_dbg(smb_fname),
7725 strerror(errno)));
7726 reply_nterror(req, map_nt_error_from_unix(errno));
7727 return;
7731 DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d "
7732 "totdata=%d\n", tran_call, smb_fname_str_dbg(smb_fname),
7733 fsp ? fsp->fnum : -1, info_level,total_data));
7735 /* Realloc the parameter size */
7736 *pparams = (char *)SMB_REALLOC(*pparams,2);
7737 if (*pparams == NULL) {
7738 reply_nterror(req, NT_STATUS_NO_MEMORY);
7739 return;
7741 params = *pparams;
7743 SSVAL(params,0,0);
7745 status = smbd_do_setfilepathinfo(conn, req, req,
7746 info_level,
7747 fsp,
7748 smb_fname,
7749 ppdata, total_data,
7750 &data_return_size);
7751 if (!NT_STATUS_IS_OK(status)) {
7752 if (open_was_deferred(req->mid)) {
7753 /* We have re-scheduled this call. */
7754 return;
7756 if (blocking_lock_was_deferred(req->mid)) {
7757 /* We have re-scheduled this call. */
7758 return;
7760 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7761 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7762 ERRSRV, ERRbadpath);
7763 return;
7765 if (info_level == SMB_POSIX_PATH_OPEN) {
7766 reply_openerror(req, status);
7767 return;
7770 reply_nterror(req, status);
7771 return;
7774 send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size,
7775 max_data_bytes);
7777 return;
7780 /****************************************************************************
7781 Reply to a TRANS2_MKDIR (make directory with extended attributes).
7782 ****************************************************************************/
7784 static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
7785 char **pparams, int total_params,
7786 char **ppdata, int total_data,
7787 unsigned int max_data_bytes)
7789 struct smb_filename *smb_dname = NULL;
7790 char *params = *pparams;
7791 char *pdata = *ppdata;
7792 char *directory = NULL;
7793 NTSTATUS status = NT_STATUS_OK;
7794 struct ea_list *ea_list = NULL;
7795 TALLOC_CTX *ctx = talloc_tos();
7797 if (!CAN_WRITE(conn)) {
7798 reply_doserror(req, ERRSRV, ERRaccess);
7799 return;
7802 if (total_params < 5) {
7803 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7804 return;
7807 srvstr_get_path(ctx, params, req->flags2, &directory, &params[4],
7808 total_params - 4, STR_TERMINATE,
7809 &status);
7810 if (!NT_STATUS_IS_OK(status)) {
7811 reply_nterror(req, status);
7812 return;
7815 DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
7817 status = filename_convert(ctx,
7818 conn,
7819 req->flags2 & FLAGS2_DFS_PATHNAMES,
7820 directory,
7822 NULL,
7823 &smb_dname);
7825 if (!NT_STATUS_IS_OK(status)) {
7826 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7827 reply_botherror(req,
7828 NT_STATUS_PATH_NOT_COVERED,
7829 ERRSRV, ERRbadpath);
7830 return;
7832 reply_nterror(req, status);
7833 return;
7836 /* Any data in this call is an EA list. */
7837 if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
7838 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
7839 goto out;
7843 * OS/2 workplace shell seems to send SET_EA requests of "null"
7844 * length (4 bytes containing IVAL 4).
7845 * They seem to have no effect. Bug #3212. JRA.
7848 if (total_data != 4) {
7849 if (total_data < 10) {
7850 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7851 goto out;
7854 if (IVAL(pdata,0) > total_data) {
7855 DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
7856 IVAL(pdata,0), (unsigned int)total_data));
7857 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7858 goto out;
7861 ea_list = read_ea_list(talloc_tos(), pdata + 4,
7862 total_data - 4);
7863 if (!ea_list) {
7864 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7865 goto out;
7868 /* If total_data == 4 Windows doesn't care what values
7869 * are placed in that field, it just ignores them.
7870 * The System i QNTC IBM SMB client puts bad values here,
7871 * so ignore them. */
7873 status = create_directory(conn, req, smb_dname);
7875 if (!NT_STATUS_IS_OK(status)) {
7876 reply_nterror(req, status);
7877 goto out;
7880 /* Try and set any given EA. */
7881 if (ea_list) {
7882 status = set_ea(conn, NULL, smb_dname, ea_list);
7883 if (!NT_STATUS_IS_OK(status)) {
7884 reply_nterror(req, status);
7885 goto out;
7889 /* Realloc the parameter and data sizes */
7890 *pparams = (char *)SMB_REALLOC(*pparams,2);
7891 if(*pparams == NULL) {
7892 reply_nterror(req, NT_STATUS_NO_MEMORY);
7893 goto out;
7895 params = *pparams;
7897 SSVAL(params,0,0);
7899 send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes);
7901 out:
7902 TALLOC_FREE(smb_dname);
7903 return;
7906 /****************************************************************************
7907 Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
7908 We don't actually do this - we just send a null response.
7909 ****************************************************************************/
7911 static void call_trans2findnotifyfirst(connection_struct *conn,
7912 struct smb_request *req,
7913 char **pparams, int total_params,
7914 char **ppdata, int total_data,
7915 unsigned int max_data_bytes)
7917 char *params = *pparams;
7918 uint16 info_level;
7920 if (total_params < 6) {
7921 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7922 return;
7925 info_level = SVAL(params,4);
7926 DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
7928 switch (info_level) {
7929 case 1:
7930 case 2:
7931 break;
7932 default:
7933 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
7934 return;
7937 /* Realloc the parameter and data sizes */
7938 *pparams = (char *)SMB_REALLOC(*pparams,6);
7939 if (*pparams == NULL) {
7940 reply_nterror(req, NT_STATUS_NO_MEMORY);
7941 return;
7943 params = *pparams;
7945 SSVAL(params,0,fnf_handle);
7946 SSVAL(params,2,0); /* No changes */
7947 SSVAL(params,4,0); /* No EA errors */
7949 fnf_handle++;
7951 if(fnf_handle == 0)
7952 fnf_handle = 257;
7954 send_trans2_replies(conn, req, params, 6, *ppdata, 0, max_data_bytes);
7956 return;
7959 /****************************************************************************
7960 Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
7961 changes). Currently this does nothing.
7962 ****************************************************************************/
7964 static void call_trans2findnotifynext(connection_struct *conn,
7965 struct smb_request *req,
7966 char **pparams, int total_params,
7967 char **ppdata, int total_data,
7968 unsigned int max_data_bytes)
7970 char *params = *pparams;
7972 DEBUG(3,("call_trans2findnotifynext\n"));
7974 /* Realloc the parameter and data sizes */
7975 *pparams = (char *)SMB_REALLOC(*pparams,4);
7976 if (*pparams == NULL) {
7977 reply_nterror(req, NT_STATUS_NO_MEMORY);
7978 return;
7980 params = *pparams;
7982 SSVAL(params,0,0); /* No changes */
7983 SSVAL(params,2,0); /* No EA errors */
7985 send_trans2_replies(conn, req, params, 4, *ppdata, 0, max_data_bytes);
7987 return;
7990 /****************************************************************************
7991 Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
7992 ****************************************************************************/
7994 static void call_trans2getdfsreferral(connection_struct *conn,
7995 struct smb_request *req,
7996 char **pparams, int total_params,
7997 char **ppdata, int total_data,
7998 unsigned int max_data_bytes)
8000 char *params = *pparams;
8001 char *pathname = NULL;
8002 int reply_size = 0;
8003 int max_referral_level;
8004 NTSTATUS status = NT_STATUS_OK;
8005 TALLOC_CTX *ctx = talloc_tos();
8007 DEBUG(10,("call_trans2getdfsreferral\n"));
8009 if (total_params < 3) {
8010 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8011 return;
8014 max_referral_level = SVAL(params,0);
8016 if(!lp_host_msdfs()) {
8017 reply_doserror(req, ERRDOS, ERRbadfunc);
8018 return;
8021 srvstr_pull_talloc(ctx, params, req->flags2, &pathname, &params[2],
8022 total_params - 2, STR_TERMINATE);
8023 if (!pathname) {
8024 reply_nterror(req, NT_STATUS_NOT_FOUND);
8025 return;
8027 if((reply_size = setup_dfs_referral(conn, pathname, max_referral_level,
8028 ppdata,&status)) < 0) {
8029 reply_nterror(req, status);
8030 return;
8033 SSVAL(req->inbuf, smb_flg2,
8034 SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
8035 send_trans2_replies(conn, req,0,0,*ppdata,reply_size, max_data_bytes);
8037 return;
8040 #define LMCAT_SPL 0x53
8041 #define LMFUNC_GETJOBID 0x60
8043 /****************************************************************************
8044 Reply to a TRANS2_IOCTL - used for OS/2 printing.
8045 ****************************************************************************/
8047 static void call_trans2ioctl(connection_struct *conn,
8048 struct smb_request *req,
8049 char **pparams, int total_params,
8050 char **ppdata, int total_data,
8051 unsigned int max_data_bytes)
8053 char *pdata = *ppdata;
8054 files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
8056 /* check for an invalid fid before proceeding */
8058 if (!fsp) {
8059 reply_doserror(req, ERRDOS, ERRbadfid);
8060 return;
8063 if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
8064 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
8065 *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
8066 if (*ppdata == NULL) {
8067 reply_nterror(req, NT_STATUS_NO_MEMORY);
8068 return;
8070 pdata = *ppdata;
8072 /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
8073 CAN ACCEPT THIS IN UNICODE. JRA. */
8075 SSVAL(pdata,0,fsp->rap_print_jobid); /* Job number */
8076 srvstr_push(pdata, req->flags2, pdata + 2,
8077 global_myname(), 15,
8078 STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */
8079 srvstr_push(pdata, req->flags2, pdata+18,
8080 lp_servicename(SNUM(conn)), 13,
8081 STR_ASCII|STR_TERMINATE); /* Service name */
8082 send_trans2_replies(conn, req, *pparams, 0, *ppdata, 32,
8083 max_data_bytes);
8084 return;
8087 DEBUG(2,("Unknown TRANS2_IOCTL\n"));
8088 reply_doserror(req, ERRSRV, ERRerror);
8091 /****************************************************************************
8092 Reply to a SMBfindclose (stop trans2 directory search).
8093 ****************************************************************************/
8095 void reply_findclose(struct smb_request *req)
8097 int dptr_num;
8098 struct smbd_server_connection *sconn = smbd_server_conn;
8100 START_PROFILE(SMBfindclose);
8102 if (req->wct < 1) {
8103 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8104 END_PROFILE(SMBfindclose);
8105 return;
8108 dptr_num = SVALS(req->vwv+0, 0);
8110 DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
8112 dptr_close(sconn, &dptr_num);
8114 reply_outbuf(req, 0, 0);
8116 DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));
8118 END_PROFILE(SMBfindclose);
8119 return;
8122 /****************************************************************************
8123 Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search).
8124 ****************************************************************************/
8126 void reply_findnclose(struct smb_request *req)
8128 int dptr_num;
8130 START_PROFILE(SMBfindnclose);
8132 if (req->wct < 1) {
8133 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8134 END_PROFILE(SMBfindnclose);
8135 return;
8138 dptr_num = SVAL(req->vwv+0, 0);
8140 DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num));
8142 /* We never give out valid handles for a
8143 findnotifyfirst - so any dptr_num is ok here.
8144 Just ignore it. */
8146 reply_outbuf(req, 0, 0);
8148 DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));
8150 END_PROFILE(SMBfindnclose);
8151 return;
8154 static void handle_trans2(connection_struct *conn, struct smb_request *req,
8155 struct trans_state *state)
8157 if (Protocol >= PROTOCOL_NT1) {
8158 req->flags2 |= 0x40; /* IS_LONG_NAME */
8159 SSVAL(req->inbuf,smb_flg2,req->flags2);
8162 if (conn->encrypt_level == Required && !req->encrypted) {
8163 if (state->call != TRANSACT2_QFSINFO &&
8164 state->call != TRANSACT2_SETFSINFO) {
8165 DEBUG(0,("handle_trans2: encryption required "
8166 "with call 0x%x\n",
8167 (unsigned int)state->call));
8168 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8169 return;
8173 SMB_PERFCOUNT_SET_SUBOP(&req->pcd, state->call);
8175 /* Now we must call the relevant TRANS2 function */
8176 switch(state->call) {
8177 case TRANSACT2_OPEN:
8179 START_PROFILE(Trans2_open);
8180 call_trans2open(conn, req,
8181 &state->param, state->total_param,
8182 &state->data, state->total_data,
8183 state->max_data_return);
8184 END_PROFILE(Trans2_open);
8185 break;
8188 case TRANSACT2_FINDFIRST:
8190 START_PROFILE(Trans2_findfirst);
8191 call_trans2findfirst(conn, req,
8192 &state->param, state->total_param,
8193 &state->data, state->total_data,
8194 state->max_data_return);
8195 END_PROFILE(Trans2_findfirst);
8196 break;
8199 case TRANSACT2_FINDNEXT:
8201 START_PROFILE(Trans2_findnext);
8202 call_trans2findnext(conn, req,
8203 &state->param, state->total_param,
8204 &state->data, state->total_data,
8205 state->max_data_return);
8206 END_PROFILE(Trans2_findnext);
8207 break;
8210 case TRANSACT2_QFSINFO:
8212 START_PROFILE(Trans2_qfsinfo);
8213 call_trans2qfsinfo(conn, req,
8214 &state->param, state->total_param,
8215 &state->data, state->total_data,
8216 state->max_data_return);
8217 END_PROFILE(Trans2_qfsinfo);
8218 break;
8221 case TRANSACT2_SETFSINFO:
8223 START_PROFILE(Trans2_setfsinfo);
8224 call_trans2setfsinfo(conn, req,
8225 &state->param, state->total_param,
8226 &state->data, state->total_data,
8227 state->max_data_return);
8228 END_PROFILE(Trans2_setfsinfo);
8229 break;
8232 case TRANSACT2_QPATHINFO:
8233 case TRANSACT2_QFILEINFO:
8235 START_PROFILE(Trans2_qpathinfo);
8236 call_trans2qfilepathinfo(conn, req, state->call,
8237 &state->param, state->total_param,
8238 &state->data, state->total_data,
8239 state->max_data_return);
8240 END_PROFILE(Trans2_qpathinfo);
8241 break;
8244 case TRANSACT2_SETPATHINFO:
8245 case TRANSACT2_SETFILEINFO:
8247 START_PROFILE(Trans2_setpathinfo);
8248 call_trans2setfilepathinfo(conn, req, state->call,
8249 &state->param, state->total_param,
8250 &state->data, state->total_data,
8251 state->max_data_return);
8252 END_PROFILE(Trans2_setpathinfo);
8253 break;
8256 case TRANSACT2_FINDNOTIFYFIRST:
8258 START_PROFILE(Trans2_findnotifyfirst);
8259 call_trans2findnotifyfirst(conn, req,
8260 &state->param, state->total_param,
8261 &state->data, state->total_data,
8262 state->max_data_return);
8263 END_PROFILE(Trans2_findnotifyfirst);
8264 break;
8267 case TRANSACT2_FINDNOTIFYNEXT:
8269 START_PROFILE(Trans2_findnotifynext);
8270 call_trans2findnotifynext(conn, req,
8271 &state->param, state->total_param,
8272 &state->data, state->total_data,
8273 state->max_data_return);
8274 END_PROFILE(Trans2_findnotifynext);
8275 break;
8278 case TRANSACT2_MKDIR:
8280 START_PROFILE(Trans2_mkdir);
8281 call_trans2mkdir(conn, req,
8282 &state->param, state->total_param,
8283 &state->data, state->total_data,
8284 state->max_data_return);
8285 END_PROFILE(Trans2_mkdir);
8286 break;
8289 case TRANSACT2_GET_DFS_REFERRAL:
8291 START_PROFILE(Trans2_get_dfs_referral);
8292 call_trans2getdfsreferral(conn, req,
8293 &state->param, state->total_param,
8294 &state->data, state->total_data,
8295 state->max_data_return);
8296 END_PROFILE(Trans2_get_dfs_referral);
8297 break;
8300 case TRANSACT2_IOCTL:
8302 START_PROFILE(Trans2_ioctl);
8303 call_trans2ioctl(conn, req,
8304 &state->param, state->total_param,
8305 &state->data, state->total_data,
8306 state->max_data_return);
8307 END_PROFILE(Trans2_ioctl);
8308 break;
8311 default:
8312 /* Error in request */
8313 DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
8314 reply_doserror(req, ERRSRV,ERRerror);
8318 /****************************************************************************
8319 Reply to a SMBtrans2.
8320 ****************************************************************************/
8322 void reply_trans2(struct smb_request *req)
8324 connection_struct *conn = req->conn;
8325 unsigned int dsoff;
8326 unsigned int dscnt;
8327 unsigned int psoff;
8328 unsigned int pscnt;
8329 unsigned int tran_call;
8330 struct trans_state *state;
8331 NTSTATUS result;
8333 START_PROFILE(SMBtrans2);
8335 if (req->wct < 14) {
8336 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8337 END_PROFILE(SMBtrans2);
8338 return;
8341 dsoff = SVAL(req->vwv+12, 0);
8342 dscnt = SVAL(req->vwv+11, 0);
8343 psoff = SVAL(req->vwv+10, 0);
8344 pscnt = SVAL(req->vwv+9, 0);
8345 tran_call = SVAL(req->vwv+14, 0);
8347 result = allow_new_trans(conn->pending_trans, req->mid);
8348 if (!NT_STATUS_IS_OK(result)) {
8349 DEBUG(2, ("Got invalid trans2 request: %s\n",
8350 nt_errstr(result)));
8351 reply_nterror(req, result);
8352 END_PROFILE(SMBtrans2);
8353 return;
8356 if (IS_IPC(conn)) {
8357 switch (tran_call) {
8358 /* List the allowed trans2 calls on IPC$ */
8359 case TRANSACT2_OPEN:
8360 case TRANSACT2_GET_DFS_REFERRAL:
8361 case TRANSACT2_QFILEINFO:
8362 case TRANSACT2_QFSINFO:
8363 case TRANSACT2_SETFSINFO:
8364 break;
8365 default:
8366 reply_doserror(req, ERRSRV, ERRaccess);
8367 END_PROFILE(SMBtrans2);
8368 return;
8372 if ((state = TALLOC_P(conn, struct trans_state)) == NULL) {
8373 DEBUG(0, ("talloc failed\n"));
8374 reply_nterror(req, NT_STATUS_NO_MEMORY);
8375 END_PROFILE(SMBtrans2);
8376 return;
8379 state->cmd = SMBtrans2;
8381 state->mid = req->mid;
8382 state->vuid = req->vuid;
8383 state->setup_count = SVAL(req->vwv+13, 0);
8384 state->setup = NULL;
8385 state->total_param = SVAL(req->vwv+0, 0);
8386 state->param = NULL;
8387 state->total_data = SVAL(req->vwv+1, 0);
8388 state->data = NULL;
8389 state->max_param_return = SVAL(req->vwv+2, 0);
8390 state->max_data_return = SVAL(req->vwv+3, 0);
8391 state->max_setup_return = SVAL(req->vwv+4, 0);
8392 state->close_on_completion = BITSETW(req->vwv+5, 0);
8393 state->one_way = BITSETW(req->vwv+5, 1);
8395 state->call = tran_call;
8397 /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
8398 is so as a sanity check */
8399 if (state->setup_count != 1) {
8401 * Need to have rc=0 for ioctl to get job id for OS/2.
8402 * Network printing will fail if function is not successful.
8403 * Similar function in reply.c will be used if protocol
8404 * is LANMAN1.0 instead of LM1.2X002.
8405 * Until DosPrintSetJobInfo with PRJINFO3 is supported,
8406 * outbuf doesn't have to be set(only job id is used).
8408 if ( (state->setup_count == 4)
8409 && (tran_call == TRANSACT2_IOCTL)
8410 && (SVAL(req->vwv+16, 0) == LMCAT_SPL)
8411 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
8412 DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
8413 } else {
8414 DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
8415 DEBUG(2,("Transaction is %d\n",tran_call));
8416 TALLOC_FREE(state);
8417 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8418 END_PROFILE(SMBtrans2);
8419 return;
8423 if ((dscnt > state->total_data) || (pscnt > state->total_param))
8424 goto bad_param;
8426 if (state->total_data) {
8428 if (trans_oob(state->total_data, 0, dscnt)
8429 || trans_oob(smb_len(req->inbuf), dsoff, dscnt)) {
8430 goto bad_param;
8433 /* Can't use talloc here, the core routines do realloc on the
8434 * params and data. */
8435 state->data = (char *)SMB_MALLOC(state->total_data);
8436 if (state->data == NULL) {
8437 DEBUG(0,("reply_trans2: data malloc fail for %u "
8438 "bytes !\n", (unsigned int)state->total_data));
8439 TALLOC_FREE(state);
8440 reply_nterror(req, NT_STATUS_NO_MEMORY);
8441 END_PROFILE(SMBtrans2);
8442 return;
8445 memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
8448 if (state->total_param) {
8450 if (trans_oob(state->total_param, 0, pscnt)
8451 || trans_oob(smb_len(req->inbuf), psoff, pscnt)) {
8452 goto bad_param;
8455 /* Can't use talloc here, the core routines do realloc on the
8456 * params and data. */
8457 state->param = (char *)SMB_MALLOC(state->total_param);
8458 if (state->param == NULL) {
8459 DEBUG(0,("reply_trans: param malloc fail for %u "
8460 "bytes !\n", (unsigned int)state->total_param));
8461 SAFE_FREE(state->data);
8462 TALLOC_FREE(state);
8463 reply_nterror(req, NT_STATUS_NO_MEMORY);
8464 END_PROFILE(SMBtrans2);
8465 return;
8468 memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
8471 state->received_data = dscnt;
8472 state->received_param = pscnt;
8474 if ((state->received_param == state->total_param) &&
8475 (state->received_data == state->total_data)) {
8477 handle_trans2(conn, req, state);
8479 SAFE_FREE(state->data);
8480 SAFE_FREE(state->param);
8481 TALLOC_FREE(state);
8482 END_PROFILE(SMBtrans2);
8483 return;
8486 DLIST_ADD(conn->pending_trans, state);
8488 /* We need to send an interim response then receive the rest
8489 of the parameter/data bytes */
8490 reply_outbuf(req, 0, 0);
8491 show_msg((char *)req->outbuf);
8492 END_PROFILE(SMBtrans2);
8493 return;
8495 bad_param:
8497 DEBUG(0,("reply_trans2: invalid trans parameters\n"));
8498 SAFE_FREE(state->data);
8499 SAFE_FREE(state->param);
8500 TALLOC_FREE(state);
8501 END_PROFILE(SMBtrans2);
8502 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8506 /****************************************************************************
8507 Reply to a SMBtranss2
8508 ****************************************************************************/
8510 void reply_transs2(struct smb_request *req)
8512 connection_struct *conn = req->conn;
8513 unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
8514 struct trans_state *state;
8516 START_PROFILE(SMBtranss2);
8518 show_msg((char *)req->inbuf);
8520 if (req->wct < 8) {
8521 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8522 END_PROFILE(SMBtranss2);
8523 return;
8526 for (state = conn->pending_trans; state != NULL;
8527 state = state->next) {
8528 if (state->mid == req->mid) {
8529 break;
8533 if ((state == NULL) || (state->cmd != SMBtrans2)) {
8534 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8535 END_PROFILE(SMBtranss2);
8536 return;
8539 /* Revise state->total_param and state->total_data in case they have
8540 changed downwards */
8542 if (SVAL(req->vwv+0, 0) < state->total_param)
8543 state->total_param = SVAL(req->vwv+0, 0);
8544 if (SVAL(req->vwv+1, 0) < state->total_data)
8545 state->total_data = SVAL(req->vwv+1, 0);
8547 pcnt = SVAL(req->vwv+2, 0);
8548 poff = SVAL(req->vwv+3, 0);
8549 pdisp = SVAL(req->vwv+4, 0);
8551 dcnt = SVAL(req->vwv+5, 0);
8552 doff = SVAL(req->vwv+6, 0);
8553 ddisp = SVAL(req->vwv+7, 0);
8555 state->received_param += pcnt;
8556 state->received_data += dcnt;
8558 if ((state->received_data > state->total_data) ||
8559 (state->received_param > state->total_param))
8560 goto bad_param;
8562 if (pcnt) {
8563 if (trans_oob(state->total_param, pdisp, pcnt)
8564 || trans_oob(smb_len(req->inbuf), poff, pcnt)) {
8565 goto bad_param;
8567 memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
8570 if (dcnt) {
8571 if (trans_oob(state->total_data, ddisp, dcnt)
8572 || trans_oob(smb_len(req->inbuf), doff, dcnt)) {
8573 goto bad_param;
8575 memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
8578 if ((state->received_param < state->total_param) ||
8579 (state->received_data < state->total_data)) {
8580 END_PROFILE(SMBtranss2);
8581 return;
8584 handle_trans2(conn, req, state);
8586 DLIST_REMOVE(conn->pending_trans, state);
8587 SAFE_FREE(state->data);
8588 SAFE_FREE(state->param);
8589 TALLOC_FREE(state);
8591 END_PROFILE(SMBtranss2);
8592 return;
8594 bad_param:
8596 DEBUG(0,("reply_transs2: invalid trans parameters\n"));
8597 DLIST_REMOVE(conn->pending_trans, state);
8598 SAFE_FREE(state->data);
8599 SAFE_FREE(state->param);
8600 TALLOC_FREE(state);
8601 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8602 END_PROFILE(SMBtranss2);
8603 return;