s3:smbd: add a generic smbd_dirptr_lanman2_entry() function
[Samba/cd1.git] / source3 / smbd / trans2.c
blob56651b44ec5687057d837cfd10aabc2a267ab2aa
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 *pnames = NULL;
160 *pnum_names = 0;
161 return NT_STATUS_OK;
165 * TALLOC the result early to get the talloc hierarchy right.
168 names = TALLOC_ARRAY(mem_ctx, char *, 1);
169 if (names == NULL) {
170 DEBUG(0, ("talloc failed\n"));
171 return NT_STATUS_NO_MEMORY;
174 while (ea_namelist_size <= 65536) {
176 ea_namelist = TALLOC_REALLOC_ARRAY(
177 names, ea_namelist, char, ea_namelist_size);
178 if (ea_namelist == NULL) {
179 DEBUG(0, ("talloc failed\n"));
180 TALLOC_FREE(names);
181 return NT_STATUS_NO_MEMORY;
184 if (fsp && fsp->fh->fd != -1) {
185 sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
186 ea_namelist_size);
187 } else {
188 sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist,
189 ea_namelist_size);
192 if ((sizeret == -1) && (errno == ERANGE)) {
193 ea_namelist_size *= 2;
195 else {
196 break;
200 if (sizeret == -1) {
201 TALLOC_FREE(names);
202 return map_nt_error_from_unix(errno);
205 DEBUG(10, ("get_ea_list_from_file: ea_namelist size = %u\n",
206 (unsigned int)sizeret));
208 if (sizeret == 0) {
209 TALLOC_FREE(names);
210 *pnames = NULL;
211 *pnum_names = 0;
212 return NT_STATUS_OK;
216 * Ensure the result is 0-terminated
219 if (ea_namelist[sizeret-1] != '\0') {
220 TALLOC_FREE(names);
221 return NT_STATUS_INTERNAL_ERROR;
225 * count the names
227 num_names = 0;
229 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
230 num_names += 1;
233 tmp = TALLOC_REALLOC_ARRAY(mem_ctx, names, char *, num_names);
234 if (tmp == NULL) {
235 DEBUG(0, ("talloc failed\n"));
236 TALLOC_FREE(names);
237 return NT_STATUS_NO_MEMORY;
240 names = tmp;
241 num_names = 0;
243 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
244 names[num_names++] = p;
247 *pnames = names;
248 *pnum_names = num_names;
249 return NT_STATUS_OK;
252 /****************************************************************************
253 Return a linked list of the total EA's. Plus the total size
254 ****************************************************************************/
256 static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
257 const char *fname, size_t *pea_total_len)
259 /* Get a list of all xattrs. Max namesize is 64k. */
260 size_t i, num_names;
261 char **names;
262 struct ea_list *ea_list_head = NULL;
263 NTSTATUS status;
265 *pea_total_len = 0;
267 if (!lp_ea_support(SNUM(conn))) {
268 return NULL;
271 status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
272 &names, &num_names);
274 if (!NT_STATUS_IS_OK(status) || (num_names == 0)) {
275 return NULL;
278 for (i=0; i<num_names; i++) {
279 struct ea_list *listp;
280 fstring dos_ea_name;
282 if (strnequal(names[i], "system.", 7)
283 || samba_private_attr_name(names[i]))
284 continue;
286 listp = TALLOC_P(mem_ctx, struct ea_list);
287 if (listp == NULL) {
288 return NULL;
291 if (!NT_STATUS_IS_OK(get_ea_value(mem_ctx, conn, fsp,
292 fname, names[i],
293 &listp->ea))) {
294 return NULL;
297 push_ascii_fstring(dos_ea_name, listp->ea.name);
299 *pea_total_len +=
300 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
302 DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len "
303 "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
304 (unsigned int)listp->ea.value.length));
306 DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
310 /* Add on 4 for total length. */
311 if (*pea_total_len) {
312 *pea_total_len += 4;
315 DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
316 (unsigned int)*pea_total_len));
318 return ea_list_head;
321 /****************************************************************************
322 Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer
323 that was filled.
324 ****************************************************************************/
326 static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
327 connection_struct *conn, struct ea_list *ea_list)
329 unsigned int ret_data_size = 4;
330 char *p = pdata;
332 SMB_ASSERT(total_data_size >= 4);
334 if (!lp_ea_support(SNUM(conn))) {
335 SIVAL(pdata,4,0);
336 return 4;
339 for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
340 size_t dos_namelen;
341 fstring dos_ea_name;
342 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
343 dos_namelen = strlen(dos_ea_name);
344 if (dos_namelen > 255 || dos_namelen == 0) {
345 break;
347 if (ea_list->ea.value.length > 65535) {
348 break;
350 if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
351 break;
354 /* We know we have room. */
355 SCVAL(p,0,ea_list->ea.flags);
356 SCVAL(p,1,dos_namelen);
357 SSVAL(p,2,ea_list->ea.value.length);
358 fstrcpy(p+4, dos_ea_name);
359 memcpy( p + 4 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
361 total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
362 p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
365 ret_data_size = PTR_DIFF(p, pdata);
366 DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
367 SIVAL(pdata,0,ret_data_size);
368 return ret_data_size;
371 static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
372 char *pdata,
373 unsigned int total_data_size,
374 unsigned int *ret_data_size,
375 connection_struct *conn,
376 struct ea_list *ea_list)
378 uint8_t *p = (uint8_t *)pdata;
379 uint8_t *last_start = NULL;
381 *ret_data_size = 0;
383 if (!lp_ea_support(SNUM(conn))) {
384 return NT_STATUS_NO_EAS_ON_FILE;
387 for (; ea_list; ea_list = ea_list->next) {
388 size_t dos_namelen;
389 fstring dos_ea_name;
390 size_t this_size;
392 if (last_start) {
393 SIVAL(last_start, 0, PTR_DIFF(p, last_start));
395 last_start = p;
397 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
398 dos_namelen = strlen(dos_ea_name);
399 if (dos_namelen > 255 || dos_namelen == 0) {
400 return NT_STATUS_INTERNAL_ERROR;
402 if (ea_list->ea.value.length > 65535) {
403 return NT_STATUS_INTERNAL_ERROR;
406 this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length;
408 if (ea_list->next) {
409 size_t pad = 4 - (this_size % 4);
410 this_size += pad;
413 if (this_size > total_data_size) {
414 return NT_STATUS_INFO_LENGTH_MISMATCH;
417 /* We know we have room. */
418 SIVAL(p, 0x00, 0); /* next offset */
419 SCVAL(p, 0x04, ea_list->ea.flags);
420 SCVAL(p, 0x05, dos_namelen);
421 SSVAL(p, 0x06, ea_list->ea.value.length);
422 fstrcpy((char *)(p+0x08), dos_ea_name);
423 memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
425 total_data_size -= this_size;
426 p += this_size;
429 *ret_data_size = PTR_DIFF(p, pdata);
430 DEBUG(10,("fill_ea_chained_buffer: data_size = %u\n", *ret_data_size));
431 return NT_STATUS_OK;
434 static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname)
436 size_t total_ea_len = 0;
437 TALLOC_CTX *mem_ctx = NULL;
439 if (!lp_ea_support(SNUM(conn))) {
440 return 0;
442 mem_ctx = talloc_tos();
443 (void)get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
444 return total_ea_len;
447 /****************************************************************************
448 Ensure the EA name is case insensitive by matching any existing EA name.
449 ****************************************************************************/
451 static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, const char *fname, fstring unix_ea_name)
453 size_t total_ea_len;
454 TALLOC_CTX *mem_ctx = talloc_tos();
455 struct ea_list *ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
457 for (; ea_list; ea_list = ea_list->next) {
458 if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
459 DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
460 &unix_ea_name[5], ea_list->ea.name));
461 safe_strcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-6);
462 break;
467 /****************************************************************************
468 Set or delete an extended attribute.
469 ****************************************************************************/
471 NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
472 const struct smb_filename *smb_fname, struct ea_list *ea_list)
474 char *fname = NULL;
476 if (!lp_ea_support(SNUM(conn))) {
477 return NT_STATUS_EAS_NOT_SUPPORTED;
480 /* For now setting EAs on streams isn't supported. */
481 fname = smb_fname->base_name;
483 for (;ea_list; ea_list = ea_list->next) {
484 int ret;
485 fstring unix_ea_name;
487 fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
488 fstrcat(unix_ea_name, ea_list->ea.name);
490 canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
492 DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
494 if (samba_private_attr_name(unix_ea_name)) {
495 DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
496 return NT_STATUS_ACCESS_DENIED;
499 if (ea_list->ea.value.length == 0) {
500 /* Remove the attribute. */
501 if (fsp && (fsp->fh->fd != -1)) {
502 DEBUG(10,("set_ea: deleting ea name %s on "
503 "file %s by file descriptor.\n",
504 unix_ea_name, fsp_str_dbg(fsp)));
505 ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name);
506 } else {
507 DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",
508 unix_ea_name, fname));
509 ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);
511 #ifdef ENOATTR
512 /* Removing a non existent attribute always succeeds. */
513 if (ret == -1 && errno == ENOATTR) {
514 DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",
515 unix_ea_name));
516 ret = 0;
518 #endif
519 } else {
520 if (fsp && (fsp->fh->fd != -1)) {
521 DEBUG(10,("set_ea: setting ea name %s on file "
522 "%s by file descriptor.\n",
523 unix_ea_name, fsp_str_dbg(fsp)));
524 ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name,
525 ea_list->ea.value.data, ea_list->ea.value.length, 0);
526 } else {
527 DEBUG(10,("set_ea: setting ea name %s on file %s.\n",
528 unix_ea_name, fname));
529 ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name,
530 ea_list->ea.value.data, ea_list->ea.value.length, 0);
534 if (ret == -1) {
535 #ifdef ENOTSUP
536 if (errno == ENOTSUP) {
537 return NT_STATUS_EAS_NOT_SUPPORTED;
539 #endif
540 return map_nt_error_from_unix(errno);
544 return NT_STATUS_OK;
546 /****************************************************************************
547 Read a list of EA names from an incoming data buffer. Create an ea_list with them.
548 ****************************************************************************/
550 static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
552 struct ea_list *ea_list_head = NULL;
553 size_t converted_size, offset = 0;
555 while (offset + 2 < data_size) {
556 struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
557 unsigned int namelen = CVAL(pdata,offset);
559 offset++; /* Go past the namelen byte. */
561 /* integer wrap paranioa. */
562 if ((offset + namelen < offset) || (offset + namelen < namelen) ||
563 (offset > data_size) || (namelen > data_size) ||
564 (offset + namelen >= data_size)) {
565 break;
567 /* Ensure the name is null terminated. */
568 if (pdata[offset + namelen] != '\0') {
569 return NULL;
571 if (!pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset],
572 &converted_size)) {
573 DEBUG(0,("read_ea_name_list: pull_ascii_talloc "
574 "failed: %s", strerror(errno)));
576 if (!eal->ea.name) {
577 return NULL;
580 offset += (namelen + 1); /* Go past the name + terminating zero. */
581 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
582 DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
585 return ea_list_head;
588 /****************************************************************************
589 Read one EA list entry from the buffer.
590 ****************************************************************************/
592 struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used)
594 struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
595 uint16 val_len;
596 unsigned int namelen;
597 size_t converted_size;
599 if (!eal) {
600 return NULL;
603 if (data_size < 6) {
604 return NULL;
607 eal->ea.flags = CVAL(pdata,0);
608 namelen = CVAL(pdata,1);
609 val_len = SVAL(pdata,2);
611 if (4 + namelen + 1 + val_len > data_size) {
612 return NULL;
615 /* Ensure the name is null terminated. */
616 if (pdata[namelen + 4] != '\0') {
617 return NULL;
619 if (!pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4, &converted_size)) {
620 DEBUG(0,("read_ea_list_entry: pull_ascii_talloc failed: %s",
621 strerror(errno)));
623 if (!eal->ea.name) {
624 return NULL;
627 eal->ea.value = data_blob_talloc(eal, NULL, (size_t)val_len + 1);
628 if (!eal->ea.value.data) {
629 return NULL;
632 memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len);
634 /* Ensure we're null terminated just in case we print the value. */
635 eal->ea.value.data[val_len] = '\0';
636 /* But don't count the null. */
637 eal->ea.value.length--;
639 if (pbytes_used) {
640 *pbytes_used = 4 + namelen + 1 + val_len;
643 DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name));
644 dump_data(10, eal->ea.value.data, eal->ea.value.length);
646 return eal;
649 /****************************************************************************
650 Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
651 ****************************************************************************/
653 static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
655 struct ea_list *ea_list_head = NULL;
656 size_t offset = 0;
657 size_t bytes_used = 0;
659 while (offset < data_size) {
660 struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);
662 if (!eal) {
663 return NULL;
666 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
667 offset += bytes_used;
670 return ea_list_head;
673 /****************************************************************************
674 Count the total EA size needed.
675 ****************************************************************************/
677 static size_t ea_list_size(struct ea_list *ealist)
679 fstring dos_ea_name;
680 struct ea_list *listp;
681 size_t ret = 0;
683 for (listp = ealist; listp; listp = listp->next) {
684 push_ascii_fstring(dos_ea_name, listp->ea.name);
685 ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
687 /* Add on 4 for total length. */
688 if (ret) {
689 ret += 4;
692 return ret;
695 /****************************************************************************
696 Return a union of EA's from a file list and a list of names.
697 The TALLOC context for the two lists *MUST* be identical as we steal
698 memory from one list to add to another. JRA.
699 ****************************************************************************/
701 static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *file_list, size_t *total_ea_len)
703 struct ea_list *nlistp, *flistp;
705 for (nlistp = name_list; nlistp; nlistp = nlistp->next) {
706 for (flistp = file_list; flistp; flistp = flistp->next) {
707 if (strequal(nlistp->ea.name, flistp->ea.name)) {
708 break;
712 if (flistp) {
713 /* Copy the data from this entry. */
714 nlistp->ea.flags = flistp->ea.flags;
715 nlistp->ea.value = flistp->ea.value;
716 } else {
717 /* Null entry. */
718 nlistp->ea.flags = 0;
719 ZERO_STRUCT(nlistp->ea.value);
723 *total_ea_len = ea_list_size(name_list);
724 return name_list;
727 /****************************************************************************
728 Send the required number of replies back.
729 We assume all fields other than the data fields are
730 set correctly for the type of call.
731 HACK ! Always assumes smb_setup field is zero.
732 ****************************************************************************/
734 void send_trans2_replies(connection_struct *conn,
735 struct smb_request *req,
736 const char *params,
737 int paramsize,
738 const char *pdata,
739 int datasize,
740 int max_data_bytes)
742 /* As we are using a protocol > LANMAN1 then the max_send
743 variable must have been set in the sessetupX call.
744 This takes precedence over the max_xmit field in the
745 global struct. These different max_xmit variables should
746 be merged as this is now too confusing */
748 int data_to_send = datasize;
749 int params_to_send = paramsize;
750 int useable_space;
751 const char *pp = params;
752 const char *pd = pdata;
753 int params_sent_thistime, data_sent_thistime, total_sent_thistime;
754 int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
755 int data_alignment_offset = 0;
756 bool overflow = False;
757 struct smbd_server_connection *sconn = smbd_server_conn;
758 int max_send = sconn->smb1.sessions.max_send;
760 /* Modify the data_to_send and datasize and set the error if
761 we're trying to send more than max_data_bytes. We still send
762 the part of the packet(s) that fit. Strange, but needed
763 for OS/2. */
765 if (max_data_bytes > 0 && datasize > max_data_bytes) {
766 DEBUG(5,("send_trans2_replies: max_data_bytes %d exceeded by data %d\n",
767 max_data_bytes, datasize ));
768 datasize = data_to_send = max_data_bytes;
769 overflow = True;
772 /* If there genuinely are no parameters or data to send just send the empty packet */
774 if(params_to_send == 0 && data_to_send == 0) {
775 reply_outbuf(req, 10, 0);
776 show_msg((char *)req->outbuf);
777 if (!srv_send_smb(smbd_server_fd(),
778 (char *)req->outbuf,
779 true, req->seqnum+1,
780 IS_CONN_ENCRYPTED(conn),
781 &req->pcd)) {
782 exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
784 TALLOC_FREE(req->outbuf);
785 return;
788 /* When sending params and data ensure that both are nicely aligned */
789 /* Only do this alignment when there is also data to send - else
790 can cause NT redirector problems. */
792 if (((params_to_send % 4) != 0) && (data_to_send != 0))
793 data_alignment_offset = 4 - (params_to_send % 4);
795 /* Space is bufsize minus Netbios over TCP header minus SMB header */
796 /* The alignment_offset is to align the param bytes on an even byte
797 boundary. NT 4.0 Beta needs this to work correctly. */
799 useable_space = max_send - (smb_size
800 + 2 * 10 /* wct */
801 + alignment_offset
802 + data_alignment_offset);
804 if (useable_space < 0) {
805 DEBUG(0, ("send_trans2_replies failed sanity useable_space "
806 "= %d!!!", useable_space));
807 exit_server_cleanly("send_trans2_replies: Not enough space");
810 while (params_to_send || data_to_send) {
811 /* Calculate whether we will totally or partially fill this packet */
813 total_sent_thistime = params_to_send + data_to_send;
815 /* We can never send more than useable_space */
817 * Note that 'useable_space' does not include the alignment offsets,
818 * but we must include the alignment offsets in the calculation of
819 * the length of the data we send over the wire, as the alignment offsets
820 * are sent here. Fix from Marc_Jacobsen@hp.com.
823 total_sent_thistime = MIN(total_sent_thistime, useable_space);
825 reply_outbuf(req, 10, total_sent_thistime + alignment_offset
826 + data_alignment_offset);
829 * We might have SMBtrans2s in req which was transferred to
830 * the outbuf, fix that.
832 SCVAL(req->outbuf, smb_com, SMBtrans2);
834 /* Set total params and data to be sent */
835 SSVAL(req->outbuf,smb_tprcnt,paramsize);
836 SSVAL(req->outbuf,smb_tdrcnt,datasize);
838 /* Calculate how many parameters and data we can fit into
839 * this packet. Parameters get precedence
842 params_sent_thistime = MIN(params_to_send,useable_space);
843 data_sent_thistime = useable_space - params_sent_thistime;
844 data_sent_thistime = MIN(data_sent_thistime,data_to_send);
846 SSVAL(req->outbuf,smb_prcnt, params_sent_thistime);
848 /* smb_proff is the offset from the start of the SMB header to the
849 parameter bytes, however the first 4 bytes of outbuf are
850 the Netbios over TCP header. Thus use smb_base() to subtract
851 them from the calculation */
853 SSVAL(req->outbuf,smb_proff,
854 ((smb_buf(req->outbuf)+alignment_offset)
855 - smb_base(req->outbuf)));
857 if(params_sent_thistime == 0)
858 SSVAL(req->outbuf,smb_prdisp,0);
859 else
860 /* Absolute displacement of param bytes sent in this packet */
861 SSVAL(req->outbuf,smb_prdisp,pp - params);
863 SSVAL(req->outbuf,smb_drcnt, data_sent_thistime);
864 if(data_sent_thistime == 0) {
865 SSVAL(req->outbuf,smb_droff,0);
866 SSVAL(req->outbuf,smb_drdisp, 0);
867 } else {
868 /* The offset of the data bytes is the offset of the
869 parameter bytes plus the number of parameters being sent this time */
870 SSVAL(req->outbuf, smb_droff,
871 ((smb_buf(req->outbuf)+alignment_offset)
872 - smb_base(req->outbuf))
873 + params_sent_thistime + data_alignment_offset);
874 SSVAL(req->outbuf,smb_drdisp, pd - pdata);
877 /* Initialize the padding for alignment */
879 if (alignment_offset != 0) {
880 memset(smb_buf(req->outbuf), 0, alignment_offset);
883 /* Copy the param bytes into the packet */
885 if(params_sent_thistime) {
886 memcpy((smb_buf(req->outbuf)+alignment_offset), pp,
887 params_sent_thistime);
890 /* Copy in the data bytes */
891 if(data_sent_thistime) {
892 if (data_alignment_offset != 0) {
893 memset((smb_buf(req->outbuf)+alignment_offset+
894 params_sent_thistime), 0,
895 data_alignment_offset);
897 memcpy(smb_buf(req->outbuf)+alignment_offset
898 +params_sent_thistime+data_alignment_offset,
899 pd,data_sent_thistime);
902 DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
903 params_sent_thistime, data_sent_thistime, useable_space));
904 DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
905 params_to_send, data_to_send, paramsize, datasize));
907 if (overflow) {
908 error_packet_set((char *)req->outbuf,
909 ERRDOS,ERRbufferoverflow,
910 STATUS_BUFFER_OVERFLOW,
911 __LINE__,__FILE__);
914 /* Send the packet */
915 show_msg((char *)req->outbuf);
916 if (!srv_send_smb(smbd_server_fd(),
917 (char *)req->outbuf,
918 true, req->seqnum+1,
919 IS_CONN_ENCRYPTED(conn),
920 &req->pcd))
921 exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
923 TALLOC_FREE(req->outbuf);
925 pp += params_sent_thistime;
926 pd += data_sent_thistime;
928 params_to_send -= params_sent_thistime;
929 data_to_send -= data_sent_thistime;
931 /* Sanity check */
932 if(params_to_send < 0 || data_to_send < 0) {
933 DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
934 params_to_send, data_to_send));
935 return;
939 return;
942 /****************************************************************************
943 Reply to a TRANSACT2_OPEN.
944 ****************************************************************************/
946 static void call_trans2open(connection_struct *conn,
947 struct smb_request *req,
948 char **pparams, int total_params,
949 char **ppdata, int total_data,
950 unsigned int max_data_bytes)
952 struct smb_filename *smb_fname = NULL;
953 char *params = *pparams;
954 char *pdata = *ppdata;
955 int deny_mode;
956 int32 open_attr;
957 bool oplock_request;
958 #if 0
959 bool return_additional_info;
960 int16 open_sattr;
961 time_t open_time;
962 #endif
963 int open_ofun;
964 uint32 open_size;
965 char *pname;
966 char *fname = NULL;
967 SMB_OFF_T size=0;
968 int fattr=0,mtime=0;
969 SMB_INO_T inode = 0;
970 int smb_action = 0;
971 files_struct *fsp;
972 struct ea_list *ea_list = NULL;
973 uint16 flags = 0;
974 NTSTATUS status;
975 uint32 access_mask;
976 uint32 share_mode;
977 uint32 create_disposition;
978 uint32 create_options = 0;
979 TALLOC_CTX *ctx = talloc_tos();
982 * Ensure we have enough parameters to perform the operation.
985 if (total_params < 29) {
986 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
987 goto out;
990 flags = SVAL(params, 0);
991 deny_mode = SVAL(params, 2);
992 open_attr = SVAL(params,6);
993 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
994 if (oplock_request) {
995 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
998 #if 0
999 return_additional_info = BITSETW(params,0);
1000 open_sattr = SVAL(params, 4);
1001 open_time = make_unix_date3(params+8);
1002 #endif
1003 open_ofun = SVAL(params,12);
1004 open_size = IVAL(params,14);
1005 pname = &params[28];
1007 if (IS_IPC(conn)) {
1008 reply_doserror(req, ERRSRV, ERRaccess);
1009 goto out;
1012 srvstr_get_path(ctx, params, req->flags2, &fname, pname,
1013 total_params - 28, STR_TERMINATE,
1014 &status);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 reply_nterror(req, status);
1017 goto out;
1020 DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n",
1021 fname, (unsigned int)deny_mode, (unsigned int)open_attr,
1022 (unsigned int)open_ofun, open_size));
1024 status = filename_convert(ctx,
1025 conn,
1026 req->flags2 & FLAGS2_DFS_PATHNAMES,
1027 fname,
1029 NULL,
1030 &smb_fname);
1031 if (!NT_STATUS_IS_OK(status)) {
1032 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1033 reply_botherror(req,
1034 NT_STATUS_PATH_NOT_COVERED,
1035 ERRSRV, ERRbadpath);
1036 goto out;
1038 reply_nterror(req, status);
1039 goto out;
1042 if (open_ofun == 0) {
1043 reply_nterror(req, NT_STATUS_OBJECT_NAME_COLLISION);
1044 goto out;
1047 if (!map_open_params_to_ntcreate(smb_fname, deny_mode, open_ofun,
1048 &access_mask, &share_mode,
1049 &create_disposition,
1050 &create_options)) {
1051 reply_doserror(req, ERRDOS, ERRbadaccess);
1052 goto out;
1055 /* Any data in this call is an EA list. */
1056 if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
1057 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
1058 goto out;
1061 if (total_data != 4) {
1062 if (total_data < 10) {
1063 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1064 goto out;
1067 if (IVAL(pdata,0) > total_data) {
1068 DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n",
1069 IVAL(pdata,0), (unsigned int)total_data));
1070 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1071 goto out;
1074 ea_list = read_ea_list(talloc_tos(), pdata + 4,
1075 total_data - 4);
1076 if (!ea_list) {
1077 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1078 goto out;
1080 } else if (IVAL(pdata,0) != 4) {
1081 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1082 goto out;
1085 status = SMB_VFS_CREATE_FILE(
1086 conn, /* conn */
1087 req, /* req */
1088 0, /* root_dir_fid */
1089 smb_fname, /* fname */
1090 access_mask, /* access_mask */
1091 share_mode, /* share_access */
1092 create_disposition, /* create_disposition*/
1093 create_options, /* create_options */
1094 open_attr, /* file_attributes */
1095 oplock_request, /* oplock_request */
1096 open_size, /* allocation_size */
1097 NULL, /* sd */
1098 ea_list, /* ea_list */
1099 &fsp, /* result */
1100 &smb_action); /* psbuf */
1102 if (!NT_STATUS_IS_OK(status)) {
1103 if (open_was_deferred(req->mid)) {
1104 /* We have re-scheduled this call. */
1105 goto out;
1107 reply_openerror(req, status);
1108 goto out;
1111 size = get_file_size_stat(&smb_fname->st);
1112 fattr = dos_mode(conn, smb_fname);
1113 mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
1114 inode = smb_fname->st.st_ex_ino;
1115 if (fattr & aDIR) {
1116 close_file(req, fsp, ERROR_CLOSE);
1117 reply_doserror(req, ERRDOS,ERRnoaccess);
1118 goto out;
1121 /* Realloc the size of parameters and data we will return */
1122 *pparams = (char *)SMB_REALLOC(*pparams, 30);
1123 if(*pparams == NULL ) {
1124 reply_nterror(req, NT_STATUS_NO_MEMORY);
1125 goto out;
1127 params = *pparams;
1129 SSVAL(params,0,fsp->fnum);
1130 SSVAL(params,2,fattr);
1131 srv_put_dos_date2(params,4, mtime);
1132 SIVAL(params,8, (uint32)size);
1133 SSVAL(params,12,deny_mode);
1134 SSVAL(params,14,0); /* open_type - file or directory. */
1135 SSVAL(params,16,0); /* open_state - only valid for IPC device. */
1137 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1138 smb_action |= EXTENDED_OPLOCK_GRANTED;
1141 SSVAL(params,18,smb_action);
1144 * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
1146 SIVAL(params,20,inode);
1147 SSVAL(params,24,0); /* Padding. */
1148 if (flags & 8) {
1149 uint32 ea_size = estimate_ea_size(conn, fsp,
1150 fsp->fsp_name->base_name);
1151 SIVAL(params, 26, ea_size);
1152 } else {
1153 SIVAL(params, 26, 0);
1156 /* Send the required number of replies */
1157 send_trans2_replies(conn, req, params, 30, *ppdata, 0, max_data_bytes);
1158 out:
1159 TALLOC_FREE(smb_fname);
1162 /*********************************************************
1163 Routine to check if a given string matches exactly.
1164 as a special case a mask of "." does NOT match. That
1165 is required for correct wildcard semantics
1166 Case can be significant or not.
1167 **********************************************************/
1169 static bool exact_match(bool has_wild,
1170 bool case_sensitive,
1171 const char *str,
1172 const char *mask)
1174 if (mask[0] == '.' && mask[1] == 0) {
1175 return false;
1178 if (has_wild) {
1179 return false;
1182 if (case_sensitive) {
1183 return strcmp(str,mask)==0;
1184 } else {
1185 return StrCaseCmp(str,mask) == 0;
1189 /****************************************************************************
1190 Return the filetype for UNIX extensions.
1191 ****************************************************************************/
1193 static uint32 unix_filetype(mode_t mode)
1195 if(S_ISREG(mode))
1196 return UNIX_TYPE_FILE;
1197 else if(S_ISDIR(mode))
1198 return UNIX_TYPE_DIR;
1199 #ifdef S_ISLNK
1200 else if(S_ISLNK(mode))
1201 return UNIX_TYPE_SYMLINK;
1202 #endif
1203 #ifdef S_ISCHR
1204 else if(S_ISCHR(mode))
1205 return UNIX_TYPE_CHARDEV;
1206 #endif
1207 #ifdef S_ISBLK
1208 else if(S_ISBLK(mode))
1209 return UNIX_TYPE_BLKDEV;
1210 #endif
1211 #ifdef S_ISFIFO
1212 else if(S_ISFIFO(mode))
1213 return UNIX_TYPE_FIFO;
1214 #endif
1215 #ifdef S_ISSOCK
1216 else if(S_ISSOCK(mode))
1217 return UNIX_TYPE_SOCKET;
1218 #endif
1220 DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode));
1221 return UNIX_TYPE_UNKNOWN;
1224 /****************************************************************************
1225 Map wire perms onto standard UNIX permissions. Obey share restrictions.
1226 ****************************************************************************/
1228 enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_DIR};
1230 static NTSTATUS unix_perms_from_wire( connection_struct *conn,
1231 const SMB_STRUCT_STAT *psbuf,
1232 uint32 perms,
1233 enum perm_type ptype,
1234 mode_t *ret_perms)
1236 mode_t ret = 0;
1238 if (perms == SMB_MODE_NO_CHANGE) {
1239 if (!VALID_STAT(*psbuf)) {
1240 return NT_STATUS_INVALID_PARAMETER;
1241 } else {
1242 *ret_perms = psbuf->st_ex_mode;
1243 return NT_STATUS_OK;
1247 ret |= ((perms & UNIX_X_OTH ) ? S_IXOTH : 0);
1248 ret |= ((perms & UNIX_W_OTH ) ? S_IWOTH : 0);
1249 ret |= ((perms & UNIX_R_OTH ) ? S_IROTH : 0);
1250 ret |= ((perms & UNIX_X_GRP ) ? S_IXGRP : 0);
1251 ret |= ((perms & UNIX_W_GRP ) ? S_IWGRP : 0);
1252 ret |= ((perms & UNIX_R_GRP ) ? S_IRGRP : 0);
1253 ret |= ((perms & UNIX_X_USR ) ? S_IXUSR : 0);
1254 ret |= ((perms & UNIX_W_USR ) ? S_IWUSR : 0);
1255 ret |= ((perms & UNIX_R_USR ) ? S_IRUSR : 0);
1256 #ifdef S_ISVTX
1257 ret |= ((perms & UNIX_STICKY ) ? S_ISVTX : 0);
1258 #endif
1259 #ifdef S_ISGID
1260 ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0);
1261 #endif
1262 #ifdef S_ISUID
1263 ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0);
1264 #endif
1266 switch (ptype) {
1267 case PERM_NEW_FILE:
1268 /* Apply mode mask */
1269 ret &= lp_create_mask(SNUM(conn));
1270 /* Add in force bits */
1271 ret |= lp_force_create_mode(SNUM(conn));
1272 break;
1273 case PERM_NEW_DIR:
1274 ret &= lp_dir_mask(SNUM(conn));
1275 /* Add in force bits */
1276 ret |= lp_force_dir_mode(SNUM(conn));
1277 break;
1278 case PERM_EXISTING_FILE:
1279 /* Apply mode mask */
1280 ret &= lp_security_mask(SNUM(conn));
1281 /* Add in force bits */
1282 ret |= lp_force_security_mode(SNUM(conn));
1283 break;
1284 case PERM_EXISTING_DIR:
1285 /* Apply mode mask */
1286 ret &= lp_dir_security_mask(SNUM(conn));
1287 /* Add in force bits */
1288 ret |= lp_force_dir_security_mode(SNUM(conn));
1289 break;
1292 *ret_perms = ret;
1293 return NT_STATUS_OK;
1296 /****************************************************************************
1297 Needed to show the msdfs symlinks as directories. Modifies psbuf
1298 to be a directory if it's a msdfs link.
1299 ****************************************************************************/
1301 static bool check_msdfs_link(connection_struct *conn,
1302 const char *pathname,
1303 SMB_STRUCT_STAT *psbuf)
1305 int saved_errno = errno;
1306 if(lp_host_msdfs() &&
1307 lp_msdfs_root(SNUM(conn)) &&
1308 is_msdfs_link(conn, pathname, psbuf)) {
1310 DEBUG(5,("check_msdfs_link: Masquerading msdfs link %s "
1311 "as a directory\n",
1312 pathname));
1313 psbuf->st_ex_mode = (psbuf->st_ex_mode & 0xFFF) | S_IFDIR;
1314 errno = saved_errno;
1315 return true;
1317 errno = saved_errno;
1318 return false;
1322 /****************************************************************************
1323 Get a level dependent lanman2 dir entry.
1324 ****************************************************************************/
1326 struct smbd_dirptr_lanman2_state {
1327 connection_struct *conn;
1328 uint32_t info_level;
1329 bool check_mangled_names;
1330 bool has_wild;
1331 bool got_exact_match;
1334 static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx,
1335 void *private_data,
1336 const char *dname,
1337 const char *mask,
1338 char **_fname)
1340 struct smbd_dirptr_lanman2_state *state =
1341 (struct smbd_dirptr_lanman2_state *)private_data;
1342 bool ok;
1343 char mangled_name[13]; /* mangled 8.3 name. */
1344 bool got_match;
1345 const char *fname;
1347 /* Mangle fname if it's an illegal name. */
1348 if (mangle_must_mangle(dname, state->conn->params)) {
1349 ok = name_to_8_3(dname, mangled_name,
1350 true, state->conn->params);
1351 if (!ok) {
1352 return false;
1354 fname = mangled_name;
1355 } else {
1356 fname = dname;
1359 got_match = exact_match(state->has_wild,
1360 state->conn->case_sensitive,
1361 fname, mask);
1362 state->got_exact_match = got_match;
1363 if (!got_match) {
1364 got_match = mask_match(fname, mask,
1365 state->conn->case_sensitive);
1368 if(!got_match && state->check_mangled_names &&
1369 !mangle_is_8_3(fname, false, state->conn->params)) {
1371 * It turns out that NT matches wildcards against
1372 * both long *and* short names. This may explain some
1373 * of the wildcard wierdness from old DOS clients
1374 * that some people have been seeing.... JRA.
1376 /* Force the mangling into 8.3. */
1377 ok = name_to_8_3(fname, mangled_name,
1378 false, state->conn->params);
1379 if (!ok) {
1380 return false;
1383 got_match = exact_match(state->has_wild,
1384 state->conn->case_sensitive,
1385 mangled_name, mask);
1386 state->got_exact_match = got_match;
1387 if (!got_match) {
1388 got_match = mask_match(mangled_name, mask,
1389 state->conn->case_sensitive);
1393 if (!got_match) {
1394 return false;
1397 *_fname = talloc_strdup(ctx, fname);
1398 if (*_fname == NULL) {
1399 return false;
1402 return true;
1405 static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
1406 void *private_data,
1407 struct smb_filename *smb_fname,
1408 uint32_t *_mode)
1410 struct smbd_dirptr_lanman2_state *state =
1411 (struct smbd_dirptr_lanman2_state *)private_data;
1412 bool ms_dfs_link = false;
1413 uint32_t mode = 0;
1415 if (INFO_LEVEL_IS_UNIX(state->info_level)) {
1416 if (SMB_VFS_LSTAT(state->conn, smb_fname) != 0) {
1417 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1418 "Couldn't lstat [%s] (%s)\n",
1419 smb_fname_str_dbg(smb_fname),
1420 strerror(errno)));
1421 return false;
1423 } else if (!VALID_STAT(smb_fname->st) &&
1424 SMB_VFS_STAT(state->conn, smb_fname) != 0) {
1425 /* Needed to show the msdfs symlinks as
1426 * directories */
1428 ms_dfs_link = check_msdfs_link(state->conn,
1429 smb_fname->base_name,
1430 &smb_fname->st);
1431 if (!ms_dfs_link) {
1432 DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1433 "Couldn't stat [%s] (%s)\n",
1434 smb_fname_str_dbg(smb_fname),
1435 strerror(errno)));
1436 return false;
1440 if (ms_dfs_link) {
1441 mode = dos_mode_msdfs(state->conn, smb_fname);
1442 } else {
1443 mode = dos_mode(state->conn, smb_fname);
1446 *_mode = mode;
1447 return true;
1450 static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
1451 connection_struct *conn,
1452 uint16_t flags2,
1453 uint32_t info_level,
1454 struct ea_list *name_list,
1455 bool check_mangled_names,
1456 bool requires_resume_key,
1457 uint32_t mode,
1458 const char *fname,
1459 const struct smb_filename *smb_fname,
1460 uint64_t space_remaining,
1461 uint8_t align,
1462 bool do_pad,
1463 char *base_data,
1464 char **ppdata,
1465 char *end_data,
1466 bool *out_of_space,
1467 uint64_t *last_entry_off)
1469 char *p, *q, *pdata = *ppdata;
1470 uint32_t reskey=0;
1471 uint64_t file_size = 0;
1472 uint64_t allocation_size = 0;
1473 uint32_t len;
1474 struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts;
1475 time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
1476 time_t c_date = (time_t)0;
1477 char *nameptr;
1478 char *last_entry_ptr;
1479 bool was_8_3;
1480 uint32_t nt_extmode; /* Used for NT connections instead of mode */
1481 off_t off;
1482 off_t pad = 0;
1484 *out_of_space = false;
1486 ZERO_STRUCT(mdate_ts);
1487 ZERO_STRUCT(adate_ts);
1488 ZERO_STRUCT(create_date_ts);
1489 ZERO_STRUCT(cdate_ts);
1491 if (!(mode & aDIR)) {
1492 file_size = get_file_size_stat(&smb_fname->st);
1494 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
1496 mdate_ts = smb_fname->st.st_ex_mtime;
1497 adate_ts = smb_fname->st.st_ex_atime;
1498 create_date_ts = get_create_timespec(conn, NULL, smb_fname);
1499 cdate_ts = get_change_timespec(conn, NULL, smb_fname);
1501 if (lp_dos_filetime_resolution(SNUM(conn))) {
1502 dos_filetime_timespec(&create_date_ts);
1503 dos_filetime_timespec(&mdate_ts);
1504 dos_filetime_timespec(&adate_ts);
1505 dos_filetime_timespec(&cdate_ts);
1508 create_date = convert_timespec_to_time_t(create_date_ts);
1509 mdate = convert_timespec_to_time_t(mdate_ts);
1510 adate = convert_timespec_to_time_t(adate_ts);
1511 c_date = convert_timespec_to_time_t(cdate_ts);
1513 /* align the record */
1514 off = PTR_DIFF(pdata, base_data);
1515 pad = (off + (align-1)) & ~(align-1);
1516 pad -= off;
1517 off += pad;
1518 /* initialize padding to 0 */
1519 memset(pdata, 0, pad);
1520 space_remaining -= pad;
1522 pdata += pad;
1523 p = pdata;
1524 last_entry_ptr = p;
1526 pad = 0;
1527 off = 0;
1529 nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
1531 switch (info_level) {
1532 case SMB_FIND_INFO_STANDARD:
1533 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_INFO_STANDARD\n"));
1534 if(requires_resume_key) {
1535 SIVAL(p,0,reskey);
1536 p += 4;
1538 srv_put_dos_date2(p,0,create_date);
1539 srv_put_dos_date2(p,4,adate);
1540 srv_put_dos_date2(p,8,mdate);
1541 SIVAL(p,12,(uint32)file_size);
1542 SIVAL(p,16,(uint32)allocation_size);
1543 SSVAL(p,20,mode);
1544 p += 23;
1545 nameptr = p;
1546 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1547 p += ucs2_align(base_data, p, 0);
1549 len = srvstr_push(base_data, flags2, p,
1550 fname, PTR_DIFF(end_data, p),
1551 STR_TERMINATE);
1552 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1553 if (len > 2) {
1554 SCVAL(nameptr, -1, len - 2);
1555 } else {
1556 SCVAL(nameptr, -1, 0);
1558 } else {
1559 if (len > 1) {
1560 SCVAL(nameptr, -1, len - 1);
1561 } else {
1562 SCVAL(nameptr, -1, 0);
1565 p += len;
1566 break;
1568 case SMB_FIND_EA_SIZE:
1569 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_SIZE\n"));
1570 if (requires_resume_key) {
1571 SIVAL(p,0,reskey);
1572 p += 4;
1574 srv_put_dos_date2(p,0,create_date);
1575 srv_put_dos_date2(p,4,adate);
1576 srv_put_dos_date2(p,8,mdate);
1577 SIVAL(p,12,(uint32)file_size);
1578 SIVAL(p,16,(uint32)allocation_size);
1579 SSVAL(p,20,mode);
1581 unsigned int ea_size = estimate_ea_size(conn, NULL,
1582 smb_fname->base_name);
1583 SIVAL(p,22,ea_size); /* Extended attributes */
1585 p += 27;
1586 nameptr = p - 1;
1587 len = srvstr_push(base_data, flags2,
1588 p, fname, PTR_DIFF(end_data, p),
1589 STR_TERMINATE | STR_NOALIGN);
1590 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1591 if (len > 2) {
1592 len -= 2;
1593 } else {
1594 len = 0;
1596 } else {
1597 if (len > 1) {
1598 len -= 1;
1599 } else {
1600 len = 0;
1603 SCVAL(nameptr,0,len);
1604 p += len;
1605 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1606 break;
1608 case SMB_FIND_EA_LIST:
1610 struct ea_list *file_list = NULL;
1611 size_t ea_len = 0;
1613 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_LIST\n"));
1614 if (!name_list) {
1615 return false;
1617 if (requires_resume_key) {
1618 SIVAL(p,0,reskey);
1619 p += 4;
1621 srv_put_dos_date2(p,0,create_date);
1622 srv_put_dos_date2(p,4,adate);
1623 srv_put_dos_date2(p,8,mdate);
1624 SIVAL(p,12,(uint32)file_size);
1625 SIVAL(p,16,(uint32)allocation_size);
1626 SSVAL(p,20,mode);
1627 p += 22; /* p now points to the EA area. */
1629 file_list = get_ea_list_from_file(ctx, conn, NULL,
1630 smb_fname->base_name,
1631 &ea_len);
1632 name_list = ea_list_union(name_list, file_list, &ea_len);
1634 /* We need to determine if this entry will fit in the space available. */
1635 /* Max string size is 255 bytes. */
1636 if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
1637 *out_of_space = true;
1638 DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
1639 return False; /* Not finished - just out of space */
1642 /* Push the ea_data followed by the name. */
1643 p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
1644 nameptr = p;
1645 len = srvstr_push(base_data, flags2,
1646 p + 1, fname, PTR_DIFF(end_data, p+1),
1647 STR_TERMINATE | STR_NOALIGN);
1648 if (flags2 & FLAGS2_UNICODE_STRINGS) {
1649 if (len > 2) {
1650 len -= 2;
1651 } else {
1652 len = 0;
1654 } else {
1655 if (len > 1) {
1656 len -= 1;
1657 } else {
1658 len = 0;
1661 SCVAL(nameptr,0,len);
1662 p += len + 1;
1663 SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1664 break;
1667 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
1668 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
1669 was_8_3 = mangle_is_8_3(fname, True, conn->params);
1670 p += 4;
1671 SIVAL(p,0,reskey); p += 4;
1672 put_long_date_timespec(p,create_date_ts); p += 8;
1673 put_long_date_timespec(p,adate_ts); p += 8;
1674 put_long_date_timespec(p,mdate_ts); p += 8;
1675 put_long_date_timespec(p,cdate_ts); p += 8;
1676 SOFF_T(p,0,file_size); p += 8;
1677 SOFF_T(p,0,allocation_size); p += 8;
1678 SIVAL(p,0,nt_extmode); p += 4;
1679 q = p; p += 4; /* q is placeholder for name length. */
1681 unsigned int ea_size = estimate_ea_size(conn, NULL,
1682 smb_fname->base_name);
1683 SIVAL(p,0,ea_size); /* Extended attributes */
1684 p += 4;
1686 /* Clear the short name buffer. This is
1687 * IMPORTANT as not doing so will trigger
1688 * a Win2k client bug. JRA.
1690 if (!was_8_3 && check_mangled_names) {
1691 char mangled_name[13]; /* mangled 8.3 name. */
1692 if (!name_to_8_3(fname,mangled_name,True,
1693 conn->params)) {
1694 /* Error - mangle failed ! */
1695 memset(mangled_name,'\0',12);
1697 mangled_name[12] = 0;
1698 len = srvstr_push(base_data, flags2,
1699 p+2, mangled_name, 24,
1700 STR_UPPER|STR_UNICODE);
1701 if (len < 24) {
1702 memset(p + 2 + len,'\0',24 - len);
1704 SSVAL(p, 0, len);
1705 } else {
1706 memset(p,'\0',26);
1708 p += 2 + 24;
1709 len = srvstr_push(base_data, flags2, p,
1710 fname, PTR_DIFF(end_data, p),
1711 STR_TERMINATE_ASCII);
1712 SIVAL(q,0,len);
1713 p += len;
1715 len = PTR_DIFF(p, pdata);
1716 pad = (len + (align-1)) & ~(align-1);
1718 * offset to the next entry, the caller
1719 * will overwrite it for the last entry
1720 * that's why we always include the padding
1722 SIVAL(pdata,0,pad);
1724 * set padding to zero
1726 if (do_pad) {
1727 memset(p, 0, pad - len);
1728 p = pdata + pad;
1729 } else {
1730 p = pdata + len;
1732 break;
1734 case SMB_FIND_FILE_DIRECTORY_INFO:
1735 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
1736 p += 4;
1737 SIVAL(p,0,reskey); p += 4;
1738 put_long_date_timespec(p,create_date_ts); p += 8;
1739 put_long_date_timespec(p,adate_ts); p += 8;
1740 put_long_date_timespec(p,mdate_ts); p += 8;
1741 put_long_date_timespec(p,cdate_ts); p += 8;
1742 SOFF_T(p,0,file_size); p += 8;
1743 SOFF_T(p,0,allocation_size); p += 8;
1744 SIVAL(p,0,nt_extmode); p += 4;
1745 len = srvstr_push(base_data, flags2,
1746 p + 4, fname, PTR_DIFF(end_data, p+4),
1747 STR_TERMINATE_ASCII);
1748 SIVAL(p,0,len);
1749 p += 4 + len;
1751 len = PTR_DIFF(p, pdata);
1752 pad = (len + (align-1)) & ~(align-1);
1754 * offset to the next entry, the caller
1755 * will overwrite it for the last entry
1756 * that's why we always include the padding
1758 SIVAL(pdata,0,pad);
1760 * set padding to zero
1762 if (do_pad) {
1763 memset(p, 0, pad - len);
1764 p = pdata + pad;
1765 } else {
1766 p = pdata + len;
1768 break;
1770 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
1771 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
1772 p += 4;
1773 SIVAL(p,0,reskey); p += 4;
1774 put_long_date_timespec(p,create_date_ts); p += 8;
1775 put_long_date_timespec(p,adate_ts); p += 8;
1776 put_long_date_timespec(p,mdate_ts); p += 8;
1777 put_long_date_timespec(p,cdate_ts); p += 8;
1778 SOFF_T(p,0,file_size); p += 8;
1779 SOFF_T(p,0,allocation_size); p += 8;
1780 SIVAL(p,0,nt_extmode); p += 4;
1781 q = p; p += 4; /* q is placeholder for name length. */
1783 unsigned int ea_size = estimate_ea_size(conn, NULL,
1784 smb_fname->base_name);
1785 SIVAL(p,0,ea_size); /* Extended attributes */
1786 p +=4;
1788 len = srvstr_push(base_data, flags2, p,
1789 fname, PTR_DIFF(end_data, p),
1790 STR_TERMINATE_ASCII);
1791 SIVAL(q, 0, len);
1792 p += len;
1794 len = PTR_DIFF(p, pdata);
1795 pad = (len + (align-1)) & ~(align-1);
1797 * offset to the next entry, the caller
1798 * will overwrite it for the last entry
1799 * that's why we always include the padding
1801 SIVAL(pdata,0,pad);
1803 * set padding to zero
1805 if (do_pad) {
1806 memset(p, 0, pad - len);
1807 p = pdata + pad;
1808 } else {
1809 p = pdata + len;
1811 break;
1813 case SMB_FIND_FILE_NAMES_INFO:
1814 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
1815 p += 4;
1816 SIVAL(p,0,reskey); p += 4;
1817 p += 4;
1818 /* this must *not* be null terminated or w2k gets in a loop trying to set an
1819 acl on a dir (tridge) */
1820 len = srvstr_push(base_data, flags2, p,
1821 fname, PTR_DIFF(end_data, p),
1822 STR_TERMINATE_ASCII);
1823 SIVAL(p, -4, len);
1824 p += len;
1826 len = PTR_DIFF(p, pdata);
1827 pad = (len + (align-1)) & ~(align-1);
1829 * offset to the next entry, the caller
1830 * will overwrite it for the last entry
1831 * that's why we always include the padding
1833 SIVAL(pdata,0,pad);
1835 * set padding to zero
1837 if (do_pad) {
1838 memset(p, 0, pad - len);
1839 p = pdata + pad;
1840 } else {
1841 p = pdata + len;
1843 break;
1845 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
1846 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
1847 p += 4;
1848 SIVAL(p,0,reskey); p += 4;
1849 put_long_date_timespec(p,create_date_ts); p += 8;
1850 put_long_date_timespec(p,adate_ts); p += 8;
1851 put_long_date_timespec(p,mdate_ts); p += 8;
1852 put_long_date_timespec(p,cdate_ts); p += 8;
1853 SOFF_T(p,0,file_size); p += 8;
1854 SOFF_T(p,0,allocation_size); p += 8;
1855 SIVAL(p,0,nt_extmode); p += 4;
1856 q = p; p += 4; /* q is placeholder for name length. */
1858 unsigned int ea_size = estimate_ea_size(conn, NULL,
1859 smb_fname->base_name);
1860 SIVAL(p,0,ea_size); /* Extended attributes */
1861 p +=4;
1863 SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
1864 SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
1865 SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
1866 len = srvstr_push(base_data, flags2, p,
1867 fname, PTR_DIFF(end_data, p),
1868 STR_TERMINATE_ASCII);
1869 SIVAL(q, 0, len);
1870 p += len;
1872 len = PTR_DIFF(p, pdata);
1873 pad = (len + (align-1)) & ~(align-1);
1875 * offset to the next entry, the caller
1876 * will overwrite it for the last entry
1877 * that's why we always include the padding
1879 SIVAL(pdata,0,pad);
1881 * set padding to zero
1883 if (do_pad) {
1884 memset(p, 0, pad - len);
1885 p = pdata + pad;
1886 } else {
1887 p = pdata + len;
1889 break;
1891 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
1892 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
1893 was_8_3 = mangle_is_8_3(fname, True, conn->params);
1894 p += 4;
1895 SIVAL(p,0,reskey); p += 4;
1896 put_long_date_timespec(p,create_date_ts); p += 8;
1897 put_long_date_timespec(p,adate_ts); p += 8;
1898 put_long_date_timespec(p,mdate_ts); p += 8;
1899 put_long_date_timespec(p,cdate_ts); p += 8;
1900 SOFF_T(p,0,file_size); p += 8;
1901 SOFF_T(p,0,allocation_size); p += 8;
1902 SIVAL(p,0,nt_extmode); p += 4;
1903 q = p; p += 4; /* q is placeholder for name length */
1905 unsigned int ea_size = estimate_ea_size(conn, NULL,
1906 smb_fname->base_name);
1907 SIVAL(p,0,ea_size); /* Extended attributes */
1908 p +=4;
1910 /* Clear the short name buffer. This is
1911 * IMPORTANT as not doing so will trigger
1912 * a Win2k client bug. JRA.
1914 if (!was_8_3 && check_mangled_names) {
1915 char mangled_name[13]; /* mangled 8.3 name. */
1916 if (!name_to_8_3(fname,mangled_name,True,
1917 conn->params)) {
1918 /* Error - mangle failed ! */
1919 memset(mangled_name,'\0',12);
1921 mangled_name[12] = 0;
1922 len = srvstr_push(base_data, flags2,
1923 p+2, mangled_name, 24,
1924 STR_UPPER|STR_UNICODE);
1925 SSVAL(p, 0, len);
1926 if (len < 24) {
1927 memset(p + 2 + len,'\0',24 - len);
1929 SSVAL(p, 0, len);
1930 } else {
1931 memset(p,'\0',26);
1933 p += 26;
1934 SSVAL(p,0,0); p += 2; /* Reserved ? */
1935 SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
1936 SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
1937 len = srvstr_push(base_data, flags2, p,
1938 fname, PTR_DIFF(end_data, p),
1939 STR_TERMINATE_ASCII);
1940 SIVAL(q,0,len);
1941 p += len;
1943 len = PTR_DIFF(p, pdata);
1944 pad = (len + (align-1)) & ~(align-1);
1946 * offset to the next entry, the caller
1947 * will overwrite it for the last entry
1948 * that's why we always include the padding
1950 SIVAL(pdata,0,pad);
1952 * set padding to zero
1954 if (do_pad) {
1955 memset(p, 0, pad - len);
1956 p = pdata + pad;
1957 } else {
1958 p = pdata + len;
1960 break;
1962 /* CIFS UNIX Extension. */
1964 case SMB_FIND_FILE_UNIX:
1965 case SMB_FIND_FILE_UNIX_INFO2:
1966 p+= 4;
1967 SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
1969 /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
1971 if (info_level == SMB_FIND_FILE_UNIX) {
1972 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
1973 p = store_file_unix_basic(conn, p,
1974 NULL, &smb_fname->st);
1975 len = srvstr_push(base_data, flags2, p,
1976 fname, PTR_DIFF(end_data, p),
1977 STR_TERMINATE);
1978 } else {
1979 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
1980 p = store_file_unix_basic_info2(conn, p,
1981 NULL, &smb_fname->st);
1982 nameptr = p;
1983 p += 4;
1984 len = srvstr_push(base_data, flags2, p, fname,
1985 PTR_DIFF(end_data, p), 0);
1986 SIVAL(nameptr, 0, len);
1989 p += len;
1991 len = PTR_DIFF(p, pdata);
1992 pad = (len + (align-1)) & ~(align-1);
1994 * offset to the next entry, the caller
1995 * will overwrite it for the last entry
1996 * that's why we always include the padding
1998 SIVAL(pdata,0,pad);
2000 * set padding to zero
2002 if (do_pad) {
2003 memset(p, 0, pad - len);
2004 p = pdata + pad;
2005 } else {
2006 p = pdata + len;
2008 /* End of SMB_QUERY_FILE_UNIX_BASIC */
2010 break;
2012 default:
2013 return false;
2016 if (PTR_DIFF(p,pdata) > space_remaining) {
2017 *out_of_space = true;
2018 DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
2019 return false; /* Not finished - just out of space */
2022 /* Setup the last entry pointer, as an offset from base_data */
2023 *last_entry_off = PTR_DIFF(last_entry_ptr,base_data);
2024 /* Advance the data pointer to the next slot */
2025 *ppdata = p;
2027 return true;
2030 bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
2031 connection_struct *conn,
2032 struct dptr_struct *dirptr,
2033 uint16 flags2,
2034 const char *path_mask,
2035 uint32 dirtype,
2036 int info_level,
2037 int requires_resume_key,
2038 bool dont_descend,
2039 bool ask_sharemode,
2040 uint8_t align,
2041 bool do_pad,
2042 char **ppdata,
2043 char *base_data,
2044 char *end_data,
2045 int space_remaining,
2046 bool *out_of_space,
2047 bool *got_exact_match,
2048 int *_last_entry_off,
2049 struct ea_list *name_list)
2051 const char *p;
2052 const char *mask = NULL;
2053 long prev_dirpos = 0;
2054 uint32_t mode = 0;
2055 char *fname = NULL;
2056 struct smb_filename *smb_fname = NULL;
2057 struct smbd_dirptr_lanman2_state state;
2058 bool ok;
2059 uint64_t last_entry_off = 0;
2061 ZERO_STRUCT(state);
2062 state.conn = conn;
2063 state.info_level = info_level;
2064 state.check_mangled_names = lp_manglednames(conn->params);
2065 state.has_wild = dptr_has_wild(dirptr);
2066 state.got_exact_match = false;
2068 *out_of_space = false;
2069 *got_exact_match = false;
2071 p = strrchr_m(path_mask,'/');
2072 if(p != NULL) {
2073 if(p[1] == '\0') {
2074 mask = "*.*";
2075 } else {
2076 mask = p+1;
2078 } else {
2079 mask = path_mask;
2082 ok = smbd_dirptr_get_entry(ctx,
2083 dirptr,
2084 mask,
2085 dirtype,
2086 dont_descend,
2087 ask_sharemode,
2088 smbd_dirptr_lanman2_match_fn,
2089 smbd_dirptr_lanman2_mode_fn,
2090 &state,
2091 &fname,
2092 &smb_fname,
2093 &mode,
2094 &prev_dirpos);
2095 if (!ok) {
2096 return false;
2099 *got_exact_match = state.got_exact_match;
2101 ok = smbd_marshall_dir_entry(ctx,
2102 conn,
2103 flags2,
2104 info_level,
2105 name_list,
2106 state.check_mangled_names,
2107 requires_resume_key,
2108 mode,
2109 fname,
2110 smb_fname,
2111 space_remaining,
2112 align,
2113 do_pad,
2114 base_data,
2115 ppdata,
2116 end_data,
2117 out_of_space,
2118 &last_entry_off);
2119 TALLOC_FREE(fname);
2120 TALLOC_FREE(smb_fname);
2121 if (*out_of_space) {
2122 dptr_SeekDir(dirptr, prev_dirpos);
2123 return false;
2125 if (!ok) {
2126 return false;
2129 *_last_entry_off = last_entry_off;
2130 return true;
2133 static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
2134 connection_struct *conn,
2135 struct dptr_struct *dirptr,
2136 uint16 flags2,
2137 const char *path_mask,
2138 uint32 dirtype,
2139 int info_level,
2140 int requires_resume_key,
2141 bool dont_descend,
2142 bool ask_sharemode,
2143 char **ppdata,
2144 char *base_data,
2145 char *end_data,
2146 int space_remaining,
2147 bool *out_of_space,
2148 bool *got_exact_match,
2149 int *last_entry_off,
2150 struct ea_list *name_list)
2152 bool resume_key = false;
2153 const uint8_t align = 4;
2154 const bool do_pad = true;
2156 if (requires_resume_key) {
2157 resume_key = true;
2160 return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2,
2161 path_mask, dirtype, info_level,
2162 resume_key, dont_descend, ask_sharemode,
2163 align, do_pad,
2164 ppdata, base_data, end_data,
2165 space_remaining,
2166 out_of_space, got_exact_match,
2167 last_entry_off, name_list);
2170 /****************************************************************************
2171 Reply to a TRANS2_FINDFIRST.
2172 ****************************************************************************/
2174 static void call_trans2findfirst(connection_struct *conn,
2175 struct smb_request *req,
2176 char **pparams, int total_params,
2177 char **ppdata, int total_data,
2178 unsigned int max_data_bytes)
2180 /* We must be careful here that we don't return more than the
2181 allowed number of data bytes. If this means returning fewer than
2182 maxentries then so be it. We assume that the redirector has
2183 enough room for the fixed number of parameter bytes it has
2184 requested. */
2185 struct smb_filename *smb_dname = NULL;
2186 char *params = *pparams;
2187 char *pdata = *ppdata;
2188 char *data_end;
2189 uint32 dirtype;
2190 int maxentries;
2191 uint16 findfirst_flags;
2192 bool close_after_first;
2193 bool close_if_end;
2194 bool requires_resume_key;
2195 int info_level;
2196 char *directory = NULL;
2197 char *mask = NULL;
2198 char *p;
2199 int last_entry_off=0;
2200 int dptr_num = -1;
2201 int numentries = 0;
2202 int i;
2203 bool finished = False;
2204 bool dont_descend = False;
2205 bool out_of_space = False;
2206 int space_remaining;
2207 bool mask_contains_wcard = False;
2208 struct ea_list *ea_list = NULL;
2209 NTSTATUS ntstatus = NT_STATUS_OK;
2210 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
2211 TALLOC_CTX *ctx = talloc_tos();
2212 struct dptr_struct *dirptr = NULL;
2213 struct smbd_server_connection *sconn = smbd_server_conn;
2215 if (total_params < 13) {
2216 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2217 goto out;
2220 dirtype = SVAL(params,0);
2221 maxentries = SVAL(params,2);
2222 findfirst_flags = SVAL(params,4);
2223 close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
2224 close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
2225 requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
2226 info_level = SVAL(params,6);
2228 DEBUG(3,("call_trans2findfirst: dirtype = %x, maxentries = %d, close_after_first=%d, \
2229 close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
2230 (unsigned int)dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
2231 info_level, max_data_bytes));
2233 if (!maxentries) {
2234 /* W2K3 seems to treat zero as 1. */
2235 maxentries = 1;
2238 switch (info_level) {
2239 case SMB_FIND_INFO_STANDARD:
2240 case SMB_FIND_EA_SIZE:
2241 case SMB_FIND_EA_LIST:
2242 case SMB_FIND_FILE_DIRECTORY_INFO:
2243 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
2244 case SMB_FIND_FILE_NAMES_INFO:
2245 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
2246 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
2247 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
2248 break;
2249 case SMB_FIND_FILE_UNIX:
2250 case SMB_FIND_FILE_UNIX_INFO2:
2251 /* Always use filesystem for UNIX mtime query. */
2252 ask_sharemode = false;
2253 if (!lp_unix_extensions()) {
2254 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2255 goto out;
2257 break;
2258 default:
2259 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2260 goto out;
2263 srvstr_get_path_wcard(ctx, params, req->flags2, &directory,
2264 params+12, total_params - 12,
2265 STR_TERMINATE, &ntstatus, &mask_contains_wcard);
2266 if (!NT_STATUS_IS_OK(ntstatus)) {
2267 reply_nterror(req, ntstatus);
2268 goto out;
2271 ntstatus = filename_convert(ctx, conn,
2272 req->flags2 & FLAGS2_DFS_PATHNAMES,
2273 directory,
2274 (UCF_SAVE_LCOMP |
2275 UCF_ALWAYS_ALLOW_WCARD_LCOMP),
2276 &mask_contains_wcard,
2277 &smb_dname);
2278 if (!NT_STATUS_IS_OK(ntstatus)) {
2279 if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
2280 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2281 ERRSRV, ERRbadpath);
2282 goto out;
2284 reply_nterror(req, ntstatus);
2285 goto out;
2288 mask = smb_dname->original_lcomp;
2290 directory = smb_dname->base_name;
2292 p = strrchr_m(directory,'/');
2293 if(p == NULL) {
2294 /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */
2295 if((directory[0] == '.') && (directory[1] == '\0')) {
2296 mask = talloc_strdup(ctx,"*");
2297 if (!mask) {
2298 reply_nterror(req, NT_STATUS_NO_MEMORY);
2299 goto out;
2301 mask_contains_wcard = True;
2303 directory = talloc_strdup(talloc_tos(), "./");
2304 if (!directory) {
2305 reply_nterror(req, NT_STATUS_NO_MEMORY);
2306 goto out;
2308 } else {
2309 *p = 0;
2312 DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
2314 if (info_level == SMB_FIND_EA_LIST) {
2315 uint32 ea_size;
2317 if (total_data < 4) {
2318 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2319 goto out;
2322 ea_size = IVAL(pdata,0);
2323 if (ea_size != total_data) {
2324 DEBUG(4,("call_trans2findfirst: Rejecting EA request with incorrect \
2325 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2326 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2327 goto out;
2330 if (!lp_ea_support(SNUM(conn))) {
2331 reply_doserror(req, ERRDOS, ERReasnotsupported);
2332 goto out;
2335 /* Pull out the list of names. */
2336 ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
2337 if (!ea_list) {
2338 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2339 goto out;
2343 *ppdata = (char *)SMB_REALLOC(
2344 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2345 if(*ppdata == NULL ) {
2346 reply_nterror(req, NT_STATUS_NO_MEMORY);
2347 goto out;
2349 pdata = *ppdata;
2350 data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2352 /* Realloc the params space */
2353 *pparams = (char *)SMB_REALLOC(*pparams, 10);
2354 if (*pparams == NULL) {
2355 reply_nterror(req, NT_STATUS_NO_MEMORY);
2356 goto out;
2358 params = *pparams;
2360 /* Save the wildcard match and attribs we are using on this directory -
2361 needed as lanman2 assumes these are being saved between calls */
2363 ntstatus = dptr_create(conn,
2364 directory,
2365 False,
2366 True,
2367 req->smbpid,
2368 mask,
2369 mask_contains_wcard,
2370 dirtype,
2371 &dirptr);
2373 if (!NT_STATUS_IS_OK(ntstatus)) {
2374 reply_nterror(req, ntstatus);
2375 goto out;
2378 dptr_num = dptr_dnum(dirptr);
2379 DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));
2381 /* Initialize per TRANS2_FIND_FIRST operation data */
2382 dptr_init_search_op(dirptr);
2384 /* We don't need to check for VOL here as this is returned by
2385 a different TRANS2 call. */
2387 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
2388 directory,lp_dontdescend(SNUM(conn))));
2389 if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
2390 dont_descend = True;
2392 p = pdata;
2393 space_remaining = max_data_bytes;
2394 out_of_space = False;
2396 for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
2397 bool got_exact_match = False;
2399 /* this is a heuristic to avoid seeking the dirptr except when
2400 absolutely necessary. It allows for a filename of about 40 chars */
2401 if (space_remaining < DIRLEN_GUESS && numentries > 0) {
2402 out_of_space = True;
2403 finished = False;
2404 } else {
2405 finished = !get_lanman2_dir_entry(ctx,
2406 conn,
2407 dirptr,
2408 req->flags2,
2409 mask,dirtype,info_level,
2410 requires_resume_key,dont_descend,
2411 ask_sharemode,
2412 &p,pdata,data_end,
2413 space_remaining, &out_of_space,
2414 &got_exact_match,
2415 &last_entry_off, ea_list);
2418 if (finished && out_of_space)
2419 finished = False;
2421 if (!finished && !out_of_space)
2422 numentries++;
2425 * As an optimisation if we know we aren't looking
2426 * for a wildcard name (ie. the name matches the wildcard exactly)
2427 * then we can finish on any (first) match.
2428 * This speeds up large directory searches. JRA.
2431 if(got_exact_match)
2432 finished = True;
2434 /* Ensure space_remaining never goes -ve. */
2435 if (PTR_DIFF(p,pdata) > max_data_bytes) {
2436 space_remaining = 0;
2437 out_of_space = true;
2438 } else {
2439 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
2443 /* Check if we can close the dirptr */
2444 if(close_after_first || (finished && close_if_end)) {
2445 DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
2446 dptr_close(sconn, &dptr_num);
2450 * If there are no matching entries we must return ERRDOS/ERRbadfile -
2451 * from observation of NT. NB. This changes to ERRDOS,ERRnofiles if
2452 * the protocol level is less than NT1. Tested with smbclient. JRA.
2453 * This should fix the OS/2 client bug #2335.
2456 if(numentries == 0) {
2457 dptr_close(sconn, &dptr_num);
2458 if (Protocol < PROTOCOL_NT1) {
2459 reply_doserror(req, ERRDOS, ERRnofiles);
2460 goto out;
2461 } else {
2462 reply_botherror(req, NT_STATUS_NO_SUCH_FILE,
2463 ERRDOS, ERRbadfile);
2464 goto out;
2468 /* At this point pdata points to numentries directory entries. */
2470 /* Set up the return parameter block */
2471 SSVAL(params,0,dptr_num);
2472 SSVAL(params,2,numentries);
2473 SSVAL(params,4,finished);
2474 SSVAL(params,6,0); /* Never an EA error */
2475 SSVAL(params,8,last_entry_off);
2477 send_trans2_replies(conn, req, params, 10, pdata, PTR_DIFF(p,pdata),
2478 max_data_bytes);
2480 if ((! *directory) && dptr_path(sconn, dptr_num)) {
2481 directory = talloc_strdup(talloc_tos(),dptr_path(sconn, dptr_num));
2482 if (!directory) {
2483 reply_nterror(req, NT_STATUS_NO_MEMORY);
2487 DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
2488 smb_fn_name(req->cmd),
2489 mask, directory, dirtype, numentries ) );
2492 * Force a name mangle here to ensure that the
2493 * mask as an 8.3 name is top of the mangled cache.
2494 * The reasons for this are subtle. Don't remove
2495 * this code unless you know what you are doing
2496 * (see PR#13758). JRA.
2499 if(!mangle_is_8_3_wildcards( mask, False, conn->params)) {
2500 char mangled_name[13];
2501 name_to_8_3(mask, mangled_name, True, conn->params);
2503 out:
2504 TALLOC_FREE(smb_dname);
2505 return;
2508 /****************************************************************************
2509 Reply to a TRANS2_FINDNEXT.
2510 ****************************************************************************/
2512 static void call_trans2findnext(connection_struct *conn,
2513 struct smb_request *req,
2514 char **pparams, int total_params,
2515 char **ppdata, int total_data,
2516 unsigned int max_data_bytes)
2518 /* We must be careful here that we don't return more than the
2519 allowed number of data bytes. If this means returning fewer than
2520 maxentries then so be it. We assume that the redirector has
2521 enough room for the fixed number of parameter bytes it has
2522 requested. */
2523 char *params = *pparams;
2524 char *pdata = *ppdata;
2525 char *data_end;
2526 int dptr_num;
2527 int maxentries;
2528 uint16 info_level;
2529 uint32 resume_key;
2530 uint16 findnext_flags;
2531 bool close_after_request;
2532 bool close_if_end;
2533 bool requires_resume_key;
2534 bool continue_bit;
2535 bool mask_contains_wcard = False;
2536 char *resume_name = NULL;
2537 const char *mask = NULL;
2538 const char *directory = NULL;
2539 char *p = NULL;
2540 uint16 dirtype;
2541 int numentries = 0;
2542 int i, last_entry_off=0;
2543 bool finished = False;
2544 bool dont_descend = False;
2545 bool out_of_space = False;
2546 int space_remaining;
2547 struct ea_list *ea_list = NULL;
2548 NTSTATUS ntstatus = NT_STATUS_OK;
2549 bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
2550 TALLOC_CTX *ctx = talloc_tos();
2551 struct dptr_struct *dirptr;
2552 struct smbd_server_connection *sconn = smbd_server_conn;
2554 if (total_params < 13) {
2555 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2556 return;
2559 dptr_num = SVAL(params,0);
2560 maxentries = SVAL(params,2);
2561 info_level = SVAL(params,4);
2562 resume_key = IVAL(params,6);
2563 findnext_flags = SVAL(params,10);
2564 close_after_request = (findnext_flags & FLAG_TRANS2_FIND_CLOSE);
2565 close_if_end = (findnext_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
2566 requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
2567 continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE);
2569 srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name,
2570 params+12,
2571 total_params - 12, STR_TERMINATE, &ntstatus,
2572 &mask_contains_wcard);
2573 if (!NT_STATUS_IS_OK(ntstatus)) {
2574 /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
2575 complain (it thinks we're asking for the directory above the shared
2576 path or an invalid name). Catch this as the resume name is only compared, never used in
2577 a file access. JRA. */
2578 srvstr_pull_talloc(ctx, params, req->flags2,
2579 &resume_name, params+12,
2580 total_params - 12,
2581 STR_TERMINATE);
2583 if (!resume_name || !(ISDOT(resume_name) || ISDOTDOT(resume_name))) {
2584 reply_nterror(req, ntstatus);
2585 return;
2589 DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \
2590 close_after_request=%d, close_if_end = %d requires_resume_key = %d \
2591 resume_key = %d resume name = %s continue=%d level = %d\n",
2592 dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end,
2593 requires_resume_key, resume_key, resume_name, continue_bit, info_level));
2595 if (!maxentries) {
2596 /* W2K3 seems to treat zero as 1. */
2597 maxentries = 1;
2600 switch (info_level) {
2601 case SMB_FIND_INFO_STANDARD:
2602 case SMB_FIND_EA_SIZE:
2603 case SMB_FIND_EA_LIST:
2604 case SMB_FIND_FILE_DIRECTORY_INFO:
2605 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
2606 case SMB_FIND_FILE_NAMES_INFO:
2607 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
2608 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
2609 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
2610 break;
2611 case SMB_FIND_FILE_UNIX:
2612 case SMB_FIND_FILE_UNIX_INFO2:
2613 /* Always use filesystem for UNIX mtime query. */
2614 ask_sharemode = false;
2615 if (!lp_unix_extensions()) {
2616 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2617 return;
2619 break;
2620 default:
2621 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
2622 return;
2625 if (info_level == SMB_FIND_EA_LIST) {
2626 uint32 ea_size;
2628 if (total_data < 4) {
2629 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2630 return;
2633 ea_size = IVAL(pdata,0);
2634 if (ea_size != total_data) {
2635 DEBUG(4,("call_trans2findnext: Rejecting EA request with incorrect \
2636 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
2637 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2638 return;
2641 if (!lp_ea_support(SNUM(conn))) {
2642 reply_doserror(req, ERRDOS, ERReasnotsupported);
2643 return;
2646 /* Pull out the list of names. */
2647 ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
2648 if (!ea_list) {
2649 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2650 return;
2654 *ppdata = (char *)SMB_REALLOC(
2655 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2656 if(*ppdata == NULL) {
2657 reply_nterror(req, NT_STATUS_NO_MEMORY);
2658 return;
2661 pdata = *ppdata;
2662 data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2664 /* Realloc the params space */
2665 *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD);
2666 if(*pparams == NULL ) {
2667 reply_nterror(req, NT_STATUS_NO_MEMORY);
2668 return;
2671 params = *pparams;
2673 /* Check that the dptr is valid */
2674 if(!(dirptr = dptr_fetch_lanman2(sconn, dptr_num))) {
2675 reply_doserror(req, ERRDOS, ERRnofiles);
2676 return;
2679 directory = dptr_path(sconn, dptr_num);
2681 /* Get the wildcard mask from the dptr */
2682 if((p = dptr_wcard(sconn, dptr_num))== NULL) {
2683 DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
2684 reply_doserror(req, ERRDOS, ERRnofiles);
2685 return;
2688 mask = p;
2690 /* Get the attr mask from the dptr */
2691 dirtype = dptr_attr(sconn, dptr_num);
2693 DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld)\n",
2694 dptr_num, mask, dirtype,
2695 (long)dirptr,
2696 dptr_TellDir(dirptr)));
2698 /* Initialize per TRANS2_FIND_NEXT operation data */
2699 dptr_init_search_op(dirptr);
2701 /* We don't need to check for VOL here as this is returned by
2702 a different TRANS2 call. */
2704 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
2705 directory,lp_dontdescend(SNUM(conn))));
2706 if (in_list(directory,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
2707 dont_descend = True;
2709 p = pdata;
2710 space_remaining = max_data_bytes;
2711 out_of_space = False;
2714 * Seek to the correct position. We no longer use the resume key but
2715 * depend on the last file name instead.
2718 if(*resume_name && !continue_bit) {
2719 SMB_STRUCT_STAT st;
2721 long current_pos = 0;
2723 * Remember, name_to_8_3 is called by
2724 * get_lanman2_dir_entry(), so the resume name
2725 * could be mangled. Ensure we check the unmangled name.
2728 if (mangle_is_mangled(resume_name, conn->params)) {
2729 char *new_resume_name = NULL;
2730 mangle_lookup_name_from_8_3(ctx,
2731 resume_name,
2732 &new_resume_name,
2733 conn->params);
2734 if (new_resume_name) {
2735 resume_name = new_resume_name;
2740 * Fix for NT redirector problem triggered by resume key indexes
2741 * changing between directory scans. We now return a resume key of 0
2742 * and instead look for the filename to continue from (also given
2743 * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
2744 * findfirst/findnext (as is usual) then the directory pointer
2745 * should already be at the correct place.
2748 finished = !dptr_SearchDir(dirptr, resume_name, &current_pos, &st);
2749 } /* end if resume_name && !continue_bit */
2751 for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
2752 bool got_exact_match = False;
2754 /* this is a heuristic to avoid seeking the dirptr except when
2755 absolutely necessary. It allows for a filename of about 40 chars */
2756 if (space_remaining < DIRLEN_GUESS && numentries > 0) {
2757 out_of_space = True;
2758 finished = False;
2759 } else {
2760 finished = !get_lanman2_dir_entry(ctx,
2761 conn,
2762 dirptr,
2763 req->flags2,
2764 mask,dirtype,info_level,
2765 requires_resume_key,dont_descend,
2766 ask_sharemode,
2767 &p,pdata,data_end,
2768 space_remaining, &out_of_space,
2769 &got_exact_match,
2770 &last_entry_off, ea_list);
2773 if (finished && out_of_space)
2774 finished = False;
2776 if (!finished && !out_of_space)
2777 numentries++;
2780 * As an optimisation if we know we aren't looking
2781 * for a wildcard name (ie. the name matches the wildcard exactly)
2782 * then we can finish on any (first) match.
2783 * This speeds up large directory searches. JRA.
2786 if(got_exact_match)
2787 finished = True;
2789 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
2792 DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
2793 smb_fn_name(req->cmd),
2794 mask, directory, dirtype, numentries ) );
2796 /* Check if we can close the dirptr */
2797 if(close_after_request || (finished && close_if_end)) {
2798 DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
2799 dptr_close(sconn, &dptr_num); /* This frees up the saved mask */
2802 /* Set up the return parameter block */
2803 SSVAL(params,0,numentries);
2804 SSVAL(params,2,finished);
2805 SSVAL(params,4,0); /* Never an EA error */
2806 SSVAL(params,6,last_entry_off);
2808 send_trans2_replies(conn, req, params, 8, pdata, PTR_DIFF(p,pdata),
2809 max_data_bytes);
2811 return;
2814 unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
2816 E_md4hash(lp_servicename(SNUM(conn)),objid);
2817 return objid;
2820 static void samba_extended_info_version(struct smb_extended_info *extended_info)
2822 SMB_ASSERT(extended_info != NULL);
2824 extended_info->samba_magic = SAMBA_EXTENDED_INFO_MAGIC;
2825 extended_info->samba_version = ((SAMBA_VERSION_MAJOR & 0xff) << 24)
2826 | ((SAMBA_VERSION_MINOR & 0xff) << 16)
2827 | ((SAMBA_VERSION_RELEASE & 0xff) << 8);
2828 #ifdef SAMBA_VERSION_REVISION
2829 extended_info->samba_version |= (tolower(*SAMBA_VERSION_REVISION) - 'a' + 1) & 0xff;
2830 #endif
2831 extended_info->samba_subversion = 0;
2832 #ifdef SAMBA_VERSION_RC_RELEASE
2833 extended_info->samba_subversion |= (SAMBA_VERSION_RC_RELEASE & 0xff) << 24;
2834 #else
2835 #ifdef SAMBA_VERSION_PRE_RELEASE
2836 extended_info->samba_subversion |= (SAMBA_VERSION_PRE_RELEASE & 0xff) << 16;
2837 #endif
2838 #endif
2839 #ifdef SAMBA_VERSION_VENDOR_PATCH
2840 extended_info->samba_subversion |= (SAMBA_VERSION_VENDOR_PATCH & 0xffff);
2841 #endif
2842 extended_info->samba_gitcommitdate = 0;
2843 #ifdef SAMBA_VERSION_GIT_COMMIT_TIME
2844 unix_to_nt_time(&extended_info->samba_gitcommitdate, SAMBA_VERSION_GIT_COMMIT_TIME);
2845 #endif
2847 memset(extended_info->samba_version_string, 0,
2848 sizeof(extended_info->samba_version_string));
2850 snprintf (extended_info->samba_version_string,
2851 sizeof(extended_info->samba_version_string),
2852 "%s", samba_version_string());
2855 NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
2856 TALLOC_CTX *mem_ctx,
2857 uint16_t info_level,
2858 uint16_t flags2,
2859 unsigned int max_data_bytes,
2860 char **ppdata,
2861 int *ret_data_len)
2863 char *pdata, *end_data;
2864 int data_len = 0, len;
2865 const char *vname = volume_label(SNUM(conn));
2866 int snum = SNUM(conn);
2867 char *fstype = lp_fstype(SNUM(conn));
2868 uint32 additional_flags = 0;
2869 struct smb_filename *smb_fname_dot = NULL;
2870 SMB_STRUCT_STAT st;
2871 NTSTATUS status;
2873 if (IS_IPC(conn)) {
2874 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
2875 DEBUG(0,("smbd_do_qfsinfo: not an allowed "
2876 "info level (0x%x) on IPC$.\n",
2877 (unsigned int)info_level));
2878 return NT_STATUS_ACCESS_DENIED;
2882 DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level));
2884 status = create_synthetic_smb_fname(talloc_tos(), ".", NULL, NULL,
2885 &smb_fname_dot);
2886 if (!NT_STATUS_IS_OK(status)) {
2887 return status;
2890 if(SMB_VFS_STAT(conn, smb_fname_dot) != 0) {
2891 DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
2892 TALLOC_FREE(smb_fname_dot);
2893 return map_nt_error_from_unix(errno);
2896 st = smb_fname_dot->st;
2897 TALLOC_FREE(smb_fname_dot);
2899 *ppdata = (char *)SMB_REALLOC(
2900 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2901 if (*ppdata == NULL) {
2902 return NT_STATUS_NO_MEMORY;
2905 pdata = *ppdata;
2906 memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2907 end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2909 switch (info_level) {
2910 case SMB_INFO_ALLOCATION:
2912 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
2913 data_len = 18;
2914 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
2915 return map_nt_error_from_unix(errno);
2918 block_size = lp_block_size(snum);
2919 if (bsize < block_size) {
2920 uint64_t factor = block_size/bsize;
2921 bsize = block_size;
2922 dsize /= factor;
2923 dfree /= factor;
2925 if (bsize > block_size) {
2926 uint64_t factor = bsize/block_size;
2927 bsize = block_size;
2928 dsize *= factor;
2929 dfree *= factor;
2931 bytes_per_sector = 512;
2932 sectors_per_unit = bsize/bytes_per_sector;
2934 DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
2935 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
2936 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2938 SIVAL(pdata,l1_idFileSystem,st.st_ex_dev);
2939 SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
2940 SIVAL(pdata,l1_cUnit,dsize);
2941 SIVAL(pdata,l1_cUnitAvail,dfree);
2942 SSVAL(pdata,l1_cbSector,bytes_per_sector);
2943 break;
2946 case SMB_INFO_VOLUME:
2947 /* Return volume name */
2949 * Add volume serial number - hash of a combination of
2950 * the called hostname and the service name.
2952 SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(get_local_machine_name())<<16) );
2954 * Win2k3 and previous mess this up by sending a name length
2955 * one byte short. I believe only older clients (OS/2 Win9x) use
2956 * this call so try fixing this by adding a terminating null to
2957 * the pushed string. The change here was adding the STR_TERMINATE. JRA.
2959 len = srvstr_push(
2960 pdata, flags2,
2961 pdata+l2_vol_szVolLabel, vname,
2962 PTR_DIFF(end_data, pdata+l2_vol_szVolLabel),
2963 STR_NOALIGN|STR_TERMINATE);
2964 SCVAL(pdata,l2_vol_cch,len);
2965 data_len = l2_vol_szVolLabel + len;
2966 DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %d, name = %s\n",
2967 (unsigned)convert_timespec_to_time_t(st.st_ex_ctime),
2968 len, vname));
2969 break;
2971 case SMB_QUERY_FS_ATTRIBUTE_INFO:
2972 case SMB_FS_ATTRIBUTE_INFORMATION:
2974 additional_flags = 0;
2975 #if defined(HAVE_SYS_QUOTAS)
2976 additional_flags |= FILE_VOLUME_QUOTAS;
2977 #endif
2979 if(lp_nt_acl_support(SNUM(conn))) {
2980 additional_flags |= FILE_PERSISTENT_ACLS;
2983 /* Capabilities are filled in at connection time through STATVFS call */
2984 additional_flags |= conn->fs_capabilities;
2986 SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
2987 FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
2988 additional_flags); /* FS ATTRIBUTES */
2990 SIVAL(pdata,4,255); /* Max filename component length */
2991 /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
2992 and will think we can't do long filenames */
2993 len = srvstr_push(pdata, flags2, pdata+12, fstype,
2994 PTR_DIFF(end_data, pdata+12),
2995 STR_UNICODE);
2996 SIVAL(pdata,8,len);
2997 data_len = 12 + len;
2998 break;
3000 case SMB_QUERY_FS_LABEL_INFO:
3001 case SMB_FS_LABEL_INFORMATION:
3002 len = srvstr_push(pdata, flags2, pdata+4, vname,
3003 PTR_DIFF(end_data, pdata+4), 0);
3004 data_len = 4 + len;
3005 SIVAL(pdata,0,len);
3006 break;
3008 case SMB_QUERY_FS_VOLUME_INFO:
3009 case SMB_FS_VOLUME_INFORMATION:
3012 * Add volume serial number - hash of a combination of
3013 * the called hostname and the service name.
3015 SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^
3016 (str_checksum(get_local_machine_name())<<16));
3018 /* Max label len is 32 characters. */
3019 len = srvstr_push(pdata, flags2, pdata+18, vname,
3020 PTR_DIFF(end_data, pdata+18),
3021 STR_UNICODE);
3022 SIVAL(pdata,12,len);
3023 data_len = 18+len;
3025 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
3026 (int)strlen(vname),vname, lp_servicename(snum)));
3027 break;
3029 case SMB_QUERY_FS_SIZE_INFO:
3030 case SMB_FS_SIZE_INFORMATION:
3032 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
3033 data_len = 24;
3034 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
3035 return map_nt_error_from_unix(errno);
3037 block_size = lp_block_size(snum);
3038 if (bsize < block_size) {
3039 uint64_t factor = block_size/bsize;
3040 bsize = block_size;
3041 dsize /= factor;
3042 dfree /= factor;
3044 if (bsize > block_size) {
3045 uint64_t factor = bsize/block_size;
3046 bsize = block_size;
3047 dsize *= factor;
3048 dfree *= factor;
3050 bytes_per_sector = 512;
3051 sectors_per_unit = bsize/bytes_per_sector;
3052 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
3053 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
3054 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
3055 SBIG_UINT(pdata,0,dsize);
3056 SBIG_UINT(pdata,8,dfree);
3057 SIVAL(pdata,16,sectors_per_unit);
3058 SIVAL(pdata,20,bytes_per_sector);
3059 break;
3062 case SMB_FS_FULL_SIZE_INFORMATION:
3064 uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
3065 data_len = 32;
3066 if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
3067 return map_nt_error_from_unix(errno);
3069 block_size = lp_block_size(snum);
3070 if (bsize < block_size) {
3071 uint64_t factor = block_size/bsize;
3072 bsize = block_size;
3073 dsize /= factor;
3074 dfree /= factor;
3076 if (bsize > block_size) {
3077 uint64_t factor = bsize/block_size;
3078 bsize = block_size;
3079 dsize *= factor;
3080 dfree *= factor;
3082 bytes_per_sector = 512;
3083 sectors_per_unit = bsize/bytes_per_sector;
3084 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
3085 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
3086 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
3087 SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
3088 SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
3089 SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
3090 SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
3091 SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
3092 break;
3095 case SMB_QUERY_FS_DEVICE_INFO:
3096 case SMB_FS_DEVICE_INFORMATION:
3097 data_len = 8;
3098 SIVAL(pdata,0,0); /* dev type */
3099 SIVAL(pdata,4,0); /* characteristics */
3100 break;
3102 #ifdef HAVE_SYS_QUOTAS
3103 case SMB_FS_QUOTA_INFORMATION:
3105 * what we have to send --metze:
3107 * Unknown1: 24 NULL bytes
3108 * Soft Quota Treshold: 8 bytes seems like uint64_t or so
3109 * Hard Quota Limit: 8 bytes seems like uint64_t or so
3110 * Quota Flags: 2 byte :
3111 * Unknown3: 6 NULL bytes
3113 * 48 bytes total
3115 * details for Quota Flags:
3117 * 0x0020 Log Limit: log if the user exceeds his Hard Quota
3118 * 0x0010 Log Warn: log if the user exceeds his Soft Quota
3119 * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
3120 * 0x0001 Enable Quotas: enable quota for this fs
3124 /* we need to fake up a fsp here,
3125 * because its not send in this call
3127 files_struct fsp;
3128 SMB_NTQUOTA_STRUCT quotas;
3130 ZERO_STRUCT(fsp);
3131 ZERO_STRUCT(quotas);
3133 fsp.conn = conn;
3134 fsp.fnum = -1;
3136 /* access check */
3137 if (conn->server_info->utok.uid != sec_initial_uid()) {
3138 DEBUG(0,("set_user_quota: access_denied "
3139 "service [%s] user [%s]\n",
3140 lp_servicename(SNUM(conn)),
3141 conn->server_info->unix_name));
3142 return NT_STATUS_ACCESS_DENIED;
3145 if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
3146 DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3147 return map_nt_error_from_unix(errno);
3150 data_len = 48;
3152 DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",
3153 lp_servicename(SNUM(conn))));
3155 /* Unknown1 24 NULL bytes*/
3156 SBIG_UINT(pdata,0,(uint64_t)0);
3157 SBIG_UINT(pdata,8,(uint64_t)0);
3158 SBIG_UINT(pdata,16,(uint64_t)0);
3160 /* Default Soft Quota 8 bytes */
3161 SBIG_UINT(pdata,24,quotas.softlim);
3163 /* Default Hard Quota 8 bytes */
3164 SBIG_UINT(pdata,32,quotas.hardlim);
3166 /* Quota flag 2 bytes */
3167 SSVAL(pdata,40,quotas.qflags);
3169 /* Unknown3 6 NULL bytes */
3170 SSVAL(pdata,42,0);
3171 SIVAL(pdata,44,0);
3173 break;
3175 #endif /* HAVE_SYS_QUOTAS */
3176 case SMB_FS_OBJECTID_INFORMATION:
3178 unsigned char objid[16];
3179 struct smb_extended_info extended_info;
3180 memcpy(pdata,create_volume_objectid(conn, objid),16);
3181 samba_extended_info_version (&extended_info);
3182 SIVAL(pdata,16,extended_info.samba_magic);
3183 SIVAL(pdata,20,extended_info.samba_version);
3184 SIVAL(pdata,24,extended_info.samba_subversion);
3185 SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
3186 memcpy(pdata+36,extended_info.samba_version_string,28);
3187 data_len = 64;
3188 break;
3192 * Query the version and capabilities of the CIFS UNIX extensions
3193 * in use.
3196 case SMB_QUERY_CIFS_UNIX_INFO:
3198 bool large_write = lp_min_receive_file_size() &&
3199 !srv_is_signing_active(smbd_server_conn);
3200 bool large_read = !srv_is_signing_active(smbd_server_conn);
3201 int encrypt_caps = 0;
3203 if (!lp_unix_extensions()) {
3204 return NT_STATUS_INVALID_LEVEL;
3207 switch (conn->encrypt_level) {
3208 case 0:
3209 encrypt_caps = 0;
3210 break;
3211 case 1:
3212 case Auto:
3213 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
3214 break;
3215 case Required:
3216 encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
3217 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
3218 large_write = false;
3219 large_read = false;
3220 break;
3223 data_len = 12;
3224 SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
3225 SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
3227 /* We have POSIX ACLs, pathname, encryption,
3228 * large read/write, and locking capability. */
3230 SBIG_UINT(pdata,4,((uint64_t)(
3231 CIFS_UNIX_POSIX_ACLS_CAP|
3232 CIFS_UNIX_POSIX_PATHNAMES_CAP|
3233 CIFS_UNIX_FCNTL_LOCKS_CAP|
3234 CIFS_UNIX_EXTATTR_CAP|
3235 CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
3236 encrypt_caps|
3237 (large_read ? CIFS_UNIX_LARGE_READ_CAP : 0) |
3238 (large_write ?
3239 CIFS_UNIX_LARGE_WRITE_CAP : 0))));
3240 break;
3243 case SMB_QUERY_POSIX_FS_INFO:
3245 int rc;
3246 vfs_statvfs_struct svfs;
3248 if (!lp_unix_extensions()) {
3249 return NT_STATUS_INVALID_LEVEL;
3252 rc = SMB_VFS_STATVFS(conn, ".", &svfs);
3254 if (!rc) {
3255 data_len = 56;
3256 SIVAL(pdata,0,svfs.OptimalTransferSize);
3257 SIVAL(pdata,4,svfs.BlockSize);
3258 SBIG_UINT(pdata,8,svfs.TotalBlocks);
3259 SBIG_UINT(pdata,16,svfs.BlocksAvail);
3260 SBIG_UINT(pdata,24,svfs.UserBlocksAvail);
3261 SBIG_UINT(pdata,32,svfs.TotalFileNodes);
3262 SBIG_UINT(pdata,40,svfs.FreeFileNodes);
3263 SBIG_UINT(pdata,48,svfs.FsIdentifier);
3264 DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
3265 #ifdef EOPNOTSUPP
3266 } else if (rc == EOPNOTSUPP) {
3267 return NT_STATUS_INVALID_LEVEL;
3268 #endif /* EOPNOTSUPP */
3269 } else {
3270 DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3271 return NT_STATUS_DOS(ERRSRV, ERRerror);
3273 break;
3276 case SMB_QUERY_POSIX_WHOAMI:
3278 uint32_t flags = 0;
3279 uint32_t sid_bytes;
3280 int i;
3282 if (!lp_unix_extensions()) {
3283 return NT_STATUS_INVALID_LEVEL;
3286 if (max_data_bytes < 40) {
3287 return NT_STATUS_BUFFER_TOO_SMALL;
3290 /* We ARE guest if global_sid_Builtin_Guests is
3291 * in our list of SIDs.
3293 if (nt_token_check_sid(&global_sid_Builtin_Guests,
3294 conn->server_info->ptok)) {
3295 flags |= SMB_WHOAMI_GUEST;
3298 /* We are NOT guest if global_sid_Authenticated_Users
3299 * is in our list of SIDs.
3301 if (nt_token_check_sid(&global_sid_Authenticated_Users,
3302 conn->server_info->ptok)) {
3303 flags &= ~SMB_WHOAMI_GUEST;
3306 /* NOTE: 8 bytes for UID/GID, irrespective of native
3307 * platform size. This matches
3308 * SMB_QUERY_FILE_UNIX_BASIC and friends.
3310 data_len = 4 /* flags */
3311 + 4 /* flag mask */
3312 + 8 /* uid */
3313 + 8 /* gid */
3314 + 4 /* ngroups */
3315 + 4 /* num_sids */
3316 + 4 /* SID bytes */
3317 + 4 /* pad/reserved */
3318 + (conn->server_info->utok.ngroups * 8)
3319 /* groups list */
3320 + (conn->server_info->ptok->num_sids *
3321 SID_MAX_SIZE)
3322 /* SID list */;
3324 SIVAL(pdata, 0, flags);
3325 SIVAL(pdata, 4, SMB_WHOAMI_MASK);
3326 SBIG_UINT(pdata, 8,
3327 (uint64_t)conn->server_info->utok.uid);
3328 SBIG_UINT(pdata, 16,
3329 (uint64_t)conn->server_info->utok.gid);
3332 if (data_len >= max_data_bytes) {
3333 /* Potential overflow, skip the GIDs and SIDs. */
3335 SIVAL(pdata, 24, 0); /* num_groups */
3336 SIVAL(pdata, 28, 0); /* num_sids */
3337 SIVAL(pdata, 32, 0); /* num_sid_bytes */
3338 SIVAL(pdata, 36, 0); /* reserved */
3340 data_len = 40;
3341 break;
3344 SIVAL(pdata, 24, conn->server_info->utok.ngroups);
3345 SIVAL(pdata, 28, conn->server_info->num_sids);
3347 /* We walk the SID list twice, but this call is fairly
3348 * infrequent, and I don't expect that it's performance
3349 * sensitive -- jpeach
3351 for (i = 0, sid_bytes = 0;
3352 i < conn->server_info->ptok->num_sids; ++i) {
3353 sid_bytes += ndr_size_dom_sid(
3354 &conn->server_info->ptok->user_sids[i],
3355 NULL,
3359 /* SID list byte count */
3360 SIVAL(pdata, 32, sid_bytes);
3362 /* 4 bytes pad/reserved - must be zero */
3363 SIVAL(pdata, 36, 0);
3364 data_len = 40;
3366 /* GID list */
3367 for (i = 0; i < conn->server_info->utok.ngroups; ++i) {
3368 SBIG_UINT(pdata, data_len,
3369 (uint64_t)conn->server_info->utok.groups[i]);
3370 data_len += 8;
3373 /* SID list */
3374 for (i = 0;
3375 i < conn->server_info->ptok->num_sids; ++i) {
3376 int sid_len = ndr_size_dom_sid(
3377 &conn->server_info->ptok->user_sids[i],
3378 NULL,
3381 sid_linearize(pdata + data_len, sid_len,
3382 &conn->server_info->ptok->user_sids[i]);
3383 data_len += sid_len;
3386 break;
3389 case SMB_MAC_QUERY_FS_INFO:
3391 * Thursby MAC extension... ONLY on NTFS filesystems
3392 * once we do streams then we don't need this
3394 if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
3395 data_len = 88;
3396 SIVAL(pdata,84,0x100); /* Don't support mac... */
3397 break;
3399 /* drop through */
3400 default:
3401 return NT_STATUS_INVALID_LEVEL;
3404 *ret_data_len = data_len;
3405 return NT_STATUS_OK;
3408 /****************************************************************************
3409 Reply to a TRANS2_QFSINFO (query filesystem info).
3410 ****************************************************************************/
3412 static void call_trans2qfsinfo(connection_struct *conn,
3413 struct smb_request *req,
3414 char **pparams, int total_params,
3415 char **ppdata, int total_data,
3416 unsigned int max_data_bytes)
3418 char *params = *pparams;
3419 uint16_t info_level;
3420 int data_len = 0;
3421 NTSTATUS status;
3423 if (total_params < 2) {
3424 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3425 return;
3428 info_level = SVAL(params,0);
3430 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
3431 if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
3432 DEBUG(0,("call_trans2qfsinfo: encryption required "
3433 "and info level 0x%x sent.\n",
3434 (unsigned int)info_level));
3435 exit_server_cleanly("encryption required "
3436 "on connection");
3437 return;
3441 DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
3443 status = smbd_do_qfsinfo(conn, req,
3444 info_level,
3445 req->flags2,
3446 max_data_bytes,
3447 ppdata, &data_len);
3448 if (!NT_STATUS_IS_OK(status)) {
3449 reply_nterror(req, status);
3450 return;
3453 send_trans2_replies(conn, req, params, 0, *ppdata, data_len,
3454 max_data_bytes);
3456 DEBUG( 4, ( "%s info_level = %d\n",
3457 smb_fn_name(req->cmd), info_level) );
3459 return;
3462 /****************************************************************************
3463 Reply to a TRANS2_SETFSINFO (set filesystem info).
3464 ****************************************************************************/
3466 static void call_trans2setfsinfo(connection_struct *conn,
3467 struct smb_request *req,
3468 char **pparams, int total_params,
3469 char **ppdata, int total_data,
3470 unsigned int max_data_bytes)
3472 char *pdata = *ppdata;
3473 char *params = *pparams;
3474 uint16 info_level;
3476 DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",lp_servicename(SNUM(conn))));
3478 /* */
3479 if (total_params < 4) {
3480 DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
3481 total_params));
3482 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3483 return;
3486 info_level = SVAL(params,2);
3488 if (IS_IPC(conn)) {
3489 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION &&
3490 info_level != SMB_SET_CIFS_UNIX_INFO) {
3491 DEBUG(0,("call_trans2setfsinfo: not an allowed "
3492 "info level (0x%x) on IPC$.\n",
3493 (unsigned int)info_level));
3494 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3495 return;
3499 if (ENCRYPTION_REQUIRED(conn) && !req->encrypted) {
3500 if (info_level != SMB_REQUEST_TRANSPORT_ENCRYPTION) {
3501 DEBUG(0,("call_trans2setfsinfo: encryption required "
3502 "and info level 0x%x sent.\n",
3503 (unsigned int)info_level));
3504 exit_server_cleanly("encryption required "
3505 "on connection");
3506 return;
3510 switch(info_level) {
3511 case SMB_SET_CIFS_UNIX_INFO:
3513 uint16 client_unix_major;
3514 uint16 client_unix_minor;
3515 uint32 client_unix_cap_low;
3516 uint32 client_unix_cap_high;
3518 if (!lp_unix_extensions()) {
3519 reply_nterror(req,
3520 NT_STATUS_INVALID_LEVEL);
3521 return;
3524 /* There should be 12 bytes of capabilities set. */
3525 if (total_data < 8) {
3526 reply_nterror(
3527 req,
3528 NT_STATUS_INVALID_PARAMETER);
3529 return;
3531 client_unix_major = SVAL(pdata,0);
3532 client_unix_minor = SVAL(pdata,2);
3533 client_unix_cap_low = IVAL(pdata,4);
3534 client_unix_cap_high = IVAL(pdata,8);
3535 /* Just print these values for now. */
3536 DEBUG(10,("call_trans2setfsinfo: set unix info. major = %u, minor = %u \
3537 cap_low = 0x%x, cap_high = 0x%x\n",
3538 (unsigned int)client_unix_major,
3539 (unsigned int)client_unix_minor,
3540 (unsigned int)client_unix_cap_low,
3541 (unsigned int)client_unix_cap_high ));
3543 /* Here is where we must switch to posix pathname processing... */
3544 if (client_unix_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3545 lp_set_posix_pathnames();
3546 mangle_change_to_posix();
3549 if ((client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) &&
3550 !(client_unix_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) {
3551 /* Client that knows how to do posix locks,
3552 * but not posix open/mkdir operations. Set a
3553 * default type for read/write checks. */
3555 lp_set_posix_default_cifsx_readwrite_locktype(POSIX_LOCK);
3558 break;
3561 case SMB_REQUEST_TRANSPORT_ENCRYPTION:
3563 NTSTATUS status;
3564 size_t param_len = 0;
3565 size_t data_len = total_data;
3567 if (!lp_unix_extensions()) {
3568 reply_nterror(
3569 req,
3570 NT_STATUS_INVALID_LEVEL);
3571 return;
3574 if (lp_smb_encrypt(SNUM(conn)) == false) {
3575 reply_nterror(
3576 req,
3577 NT_STATUS_NOT_SUPPORTED);
3578 return;
3581 DEBUG( 4,("call_trans2setfsinfo: "
3582 "request transport encryption.\n"));
3584 status = srv_request_encryption_setup(conn,
3585 (unsigned char **)ppdata,
3586 &data_len,
3587 (unsigned char **)pparams,
3588 &param_len);
3590 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
3591 !NT_STATUS_IS_OK(status)) {
3592 reply_nterror(req, status);
3593 return;
3596 send_trans2_replies(conn, req,
3597 *pparams,
3598 param_len,
3599 *ppdata,
3600 data_len,
3601 max_data_bytes);
3603 if (NT_STATUS_IS_OK(status)) {
3604 /* Server-side transport
3605 * encryption is now *on*. */
3606 status = srv_encryption_start(conn);
3607 if (!NT_STATUS_IS_OK(status)) {
3608 exit_server_cleanly(
3609 "Failure in setting "
3610 "up encrypted transport");
3613 return;
3616 case SMB_FS_QUOTA_INFORMATION:
3618 files_struct *fsp = NULL;
3619 SMB_NTQUOTA_STRUCT quotas;
3621 ZERO_STRUCT(quotas);
3623 /* access check */
3624 if ((conn->server_info->utok.uid != sec_initial_uid())
3625 ||!CAN_WRITE(conn)) {
3626 DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
3627 lp_servicename(SNUM(conn)),
3628 conn->server_info->unix_name));
3629 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
3630 return;
3633 /* note: normaly there're 48 bytes,
3634 * but we didn't use the last 6 bytes for now
3635 * --metze
3637 fsp = file_fsp(req, SVAL(params,0));
3639 if (!check_fsp_ntquota_handle(conn, req,
3640 fsp)) {
3641 DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
3642 reply_nterror(
3643 req, NT_STATUS_INVALID_HANDLE);
3644 return;
3647 if (total_data < 42) {
3648 DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n",
3649 total_data));
3650 reply_nterror(
3651 req,
3652 NT_STATUS_INVALID_PARAMETER);
3653 return;
3656 /* unknown_1 24 NULL bytes in pdata*/
3658 /* the soft quotas 8 bytes (uint64_t)*/
3659 quotas.softlim = (uint64_t)IVAL(pdata,24);
3660 #ifdef LARGE_SMB_OFF_T
3661 quotas.softlim |= (((uint64_t)IVAL(pdata,28)) << 32);
3662 #else /* LARGE_SMB_OFF_T */
3663 if ((IVAL(pdata,28) != 0)&&
3664 ((quotas.softlim != 0xFFFFFFFF)||
3665 (IVAL(pdata,28)!=0xFFFFFFFF))) {
3666 /* more than 32 bits? */
3667 reply_nterror(
3668 req,
3669 NT_STATUS_INVALID_PARAMETER);
3670 return;
3672 #endif /* LARGE_SMB_OFF_T */
3674 /* the hard quotas 8 bytes (uint64_t)*/
3675 quotas.hardlim = (uint64_t)IVAL(pdata,32);
3676 #ifdef LARGE_SMB_OFF_T
3677 quotas.hardlim |= (((uint64_t)IVAL(pdata,36)) << 32);
3678 #else /* LARGE_SMB_OFF_T */
3679 if ((IVAL(pdata,36) != 0)&&
3680 ((quotas.hardlim != 0xFFFFFFFF)||
3681 (IVAL(pdata,36)!=0xFFFFFFFF))) {
3682 /* more than 32 bits? */
3683 reply_nterror(
3684 req,
3685 NT_STATUS_INVALID_PARAMETER);
3686 return;
3688 #endif /* LARGE_SMB_OFF_T */
3690 /* quota_flags 2 bytes **/
3691 quotas.qflags = SVAL(pdata,40);
3693 /* unknown_2 6 NULL bytes follow*/
3695 /* now set the quotas */
3696 if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
3697 DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
3698 reply_nterror(req, map_nt_error_from_unix(errno));
3699 return;
3702 break;
3704 default:
3705 DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
3706 info_level));
3707 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
3708 return;
3709 break;
3713 * sending this reply works fine,
3714 * but I'm not sure it's the same
3715 * like windows do...
3716 * --metze
3718 reply_outbuf(req, 10, 0);
3721 #if defined(HAVE_POSIX_ACLS)
3722 /****************************************************************************
3723 Utility function to count the number of entries in a POSIX acl.
3724 ****************************************************************************/
3726 static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
3728 unsigned int ace_count = 0;
3729 int entry_id = SMB_ACL_FIRST_ENTRY;
3730 SMB_ACL_ENTRY_T entry;
3732 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
3733 /* get_next... */
3734 if (entry_id == SMB_ACL_FIRST_ENTRY) {
3735 entry_id = SMB_ACL_NEXT_ENTRY;
3737 ace_count++;
3739 return ace_count;
3742 /****************************************************************************
3743 Utility function to marshall a POSIX acl into wire format.
3744 ****************************************************************************/
3746 static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
3748 int entry_id = SMB_ACL_FIRST_ENTRY;
3749 SMB_ACL_ENTRY_T entry;
3751 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
3752 SMB_ACL_TAG_T tagtype;
3753 SMB_ACL_PERMSET_T permset;
3754 unsigned char perms = 0;
3755 unsigned int own_grp;
3757 /* get_next... */
3758 if (entry_id == SMB_ACL_FIRST_ENTRY) {
3759 entry_id = SMB_ACL_NEXT_ENTRY;
3762 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3763 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
3764 return False;
3767 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3768 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
3769 return False;
3772 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
3773 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
3774 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
3776 SCVAL(pdata,1,perms);
3778 switch (tagtype) {
3779 case SMB_ACL_USER_OBJ:
3780 SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
3781 own_grp = (unsigned int)pst->st_ex_uid;
3782 SIVAL(pdata,2,own_grp);
3783 SIVAL(pdata,6,0);
3784 break;
3785 case SMB_ACL_USER:
3787 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3788 if (!puid) {
3789 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
3790 return False;
3792 own_grp = (unsigned int)*puid;
3793 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
3794 SCVAL(pdata,0,SMB_POSIX_ACL_USER);
3795 SIVAL(pdata,2,own_grp);
3796 SIVAL(pdata,6,0);
3797 break;
3799 case SMB_ACL_GROUP_OBJ:
3800 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
3801 own_grp = (unsigned int)pst->st_ex_gid;
3802 SIVAL(pdata,2,own_grp);
3803 SIVAL(pdata,6,0);
3804 break;
3805 case SMB_ACL_GROUP:
3807 gid_t *pgid= (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3808 if (!pgid) {
3809 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
3810 return False;
3812 own_grp = (unsigned int)*pgid;
3813 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
3814 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
3815 SIVAL(pdata,2,own_grp);
3816 SIVAL(pdata,6,0);
3817 break;
3819 case SMB_ACL_MASK:
3820 SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
3821 SIVAL(pdata,2,0xFFFFFFFF);
3822 SIVAL(pdata,6,0xFFFFFFFF);
3823 break;
3824 case SMB_ACL_OTHER:
3825 SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
3826 SIVAL(pdata,2,0xFFFFFFFF);
3827 SIVAL(pdata,6,0xFFFFFFFF);
3828 break;
3829 default:
3830 DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
3831 return False;
3833 pdata += SMB_POSIX_ACL_ENTRY_SIZE;
3836 return True;
3838 #endif
3840 /****************************************************************************
3841 Store the FILE_UNIX_BASIC info.
3842 ****************************************************************************/
3844 static char *store_file_unix_basic(connection_struct *conn,
3845 char *pdata,
3846 files_struct *fsp,
3847 const SMB_STRUCT_STAT *psbuf)
3849 DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
3850 DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode));
3852 SOFF_T(pdata,0,get_file_size_stat(psbuf)); /* File size 64 Bit */
3853 pdata += 8;
3855 SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
3856 pdata += 8;
3858 put_long_date_timespec(pdata, psbuf->st_ex_ctime); /* Change Time 64 Bit */
3859 put_long_date_timespec(pdata+8, psbuf->st_ex_atime); /* Last access time 64 Bit */
3860 put_long_date_timespec(pdata+16, psbuf->st_ex_mtime); /* Last modification time 64 Bit */
3861 pdata += 24;
3863 SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */
3864 SIVAL(pdata,4,0);
3865 pdata += 8;
3867 SIVAL(pdata,0,psbuf->st_ex_gid); /* group id of owner */
3868 SIVAL(pdata,4,0);
3869 pdata += 8;
3871 SIVAL(pdata,0,unix_filetype(psbuf->st_ex_mode));
3872 pdata += 4;
3874 SIVAL(pdata,0,unix_dev_major(psbuf->st_ex_rdev)); /* Major device number if type is device */
3875 SIVAL(pdata,4,0);
3876 pdata += 8;
3878 SIVAL(pdata,0,unix_dev_minor(psbuf->st_ex_rdev)); /* Minor device number if type is device */
3879 SIVAL(pdata,4,0);
3880 pdata += 8;
3882 SINO_T_VAL(pdata,0,(SMB_INO_T)psbuf->st_ex_ino); /* inode number */
3883 pdata += 8;
3885 SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode)); /* Standard UNIX file permissions */
3886 SIVAL(pdata,4,0);
3887 pdata += 8;
3889 SIVAL(pdata,0,psbuf->st_ex_nlink); /* number of hard links */
3890 SIVAL(pdata,4,0);
3891 pdata += 8;
3893 return pdata;
3896 /* Forward and reverse mappings from the UNIX_INFO2 file flags field and
3897 * the chflags(2) (or equivalent) flags.
3899 * XXX: this really should be behind the VFS interface. To do this, we would
3900 * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field.
3901 * Each VFS module could then implement its own mapping as appropriate for the
3902 * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS.
3904 static const struct {unsigned stat_fflag; unsigned smb_fflag;}
3905 info2_flags_map[] =
3907 #ifdef UF_NODUMP
3908 { UF_NODUMP, EXT_DO_NOT_BACKUP },
3909 #endif
3911 #ifdef UF_IMMUTABLE
3912 { UF_IMMUTABLE, EXT_IMMUTABLE },
3913 #endif
3915 #ifdef UF_APPEND
3916 { UF_APPEND, EXT_OPEN_APPEND_ONLY },
3917 #endif
3919 #ifdef UF_HIDDEN
3920 { UF_HIDDEN, EXT_HIDDEN },
3921 #endif
3923 /* Do not remove. We need to guarantee that this array has at least one
3924 * entry to build on HP-UX.
3926 { 0, 0 }
3930 static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
3931 uint32 *smb_fflags, uint32 *smb_fmask)
3933 int i;
3935 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3936 *smb_fmask |= info2_flags_map[i].smb_fflag;
3937 if (psbuf->st_ex_flags & info2_flags_map[i].stat_fflag) {
3938 *smb_fflags |= info2_flags_map[i].smb_fflag;
3943 static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
3944 const uint32 smb_fflags,
3945 const uint32 smb_fmask,
3946 int *stat_fflags)
3948 uint32 max_fmask = 0;
3949 int i;
3951 *stat_fflags = psbuf->st_ex_flags;
3953 /* For each flags requested in smb_fmask, check the state of the
3954 * corresponding flag in smb_fflags and set or clear the matching
3955 * stat flag.
3958 for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3959 max_fmask |= info2_flags_map[i].smb_fflag;
3960 if (smb_fmask & info2_flags_map[i].smb_fflag) {
3961 if (smb_fflags & info2_flags_map[i].smb_fflag) {
3962 *stat_fflags |= info2_flags_map[i].stat_fflag;
3963 } else {
3964 *stat_fflags &= ~info2_flags_map[i].stat_fflag;
3969 /* If smb_fmask is asking to set any bits that are not supported by
3970 * our flag mappings, we should fail.
3972 if ((smb_fmask & max_fmask) != smb_fmask) {
3973 return False;
3976 return True;
3980 /* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition
3981 * of file flags and birth (create) time.
3983 static char *store_file_unix_basic_info2(connection_struct *conn,
3984 char *pdata,
3985 files_struct *fsp,
3986 const SMB_STRUCT_STAT *psbuf)
3988 uint32 file_flags = 0;
3989 uint32 flags_mask = 0;
3991 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
3993 /* Create (birth) time 64 bit */
3994 put_long_date_timespec(pdata, psbuf->st_ex_btime);
3995 pdata += 8;
3997 map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
3998 SIVAL(pdata, 0, file_flags); /* flags */
3999 SIVAL(pdata, 4, flags_mask); /* mask */
4000 pdata += 8;
4002 return pdata;
4005 static NTSTATUS marshall_stream_info(unsigned int num_streams,
4006 const struct stream_struct *streams,
4007 char *data,
4008 unsigned int max_data_bytes,
4009 unsigned int *data_size)
4011 unsigned int i;
4012 unsigned int ofs = 0;
4014 for (i = 0; i < num_streams && ofs <= max_data_bytes; i++) {
4015 unsigned int next_offset;
4016 size_t namelen;
4017 smb_ucs2_t *namebuf;
4019 if (!push_ucs2_talloc(talloc_tos(), &namebuf,
4020 streams[i].name, &namelen) ||
4021 namelen <= 2)
4023 return NT_STATUS_INVALID_PARAMETER;
4027 * name_buf is now null-terminated, we need to marshall as not
4028 * terminated
4031 namelen -= 2;
4033 SIVAL(data, ofs+4, namelen);
4034 SOFF_T(data, ofs+8, streams[i].size);
4035 SOFF_T(data, ofs+16, streams[i].alloc_size);
4036 memcpy(data+ofs+24, namebuf, namelen);
4037 TALLOC_FREE(namebuf);
4039 next_offset = ofs + 24 + namelen;
4041 if (i == num_streams-1) {
4042 SIVAL(data, ofs, 0);
4044 else {
4045 unsigned int align = ndr_align_size(next_offset, 8);
4047 memset(data+next_offset, 0, align);
4048 next_offset += align;
4050 SIVAL(data, ofs, next_offset - ofs);
4051 ofs = next_offset;
4054 ofs = next_offset;
4057 *data_size = ofs;
4059 return NT_STATUS_OK;
4062 /****************************************************************************
4063 Reply to a TRANSACT2_QFILEINFO on a PIPE !
4064 ****************************************************************************/
4066 static void call_trans2qpipeinfo(connection_struct *conn,
4067 struct smb_request *req,
4068 unsigned int tran_call,
4069 char **pparams, int total_params,
4070 char **ppdata, int total_data,
4071 unsigned int max_data_bytes)
4073 char *params = *pparams;
4074 char *pdata = *ppdata;
4075 unsigned int data_size = 0;
4076 unsigned int param_size = 2;
4077 uint16 info_level;
4078 files_struct *fsp;
4080 if (!params) {
4081 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4082 return;
4085 if (total_params < 4) {
4086 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4087 return;
4090 fsp = file_fsp(req, SVAL(params,0));
4091 if (!fsp_is_np(fsp)) {
4092 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
4093 return;
4096 info_level = SVAL(params,2);
4098 *pparams = (char *)SMB_REALLOC(*pparams,2);
4099 if (*pparams == NULL) {
4100 reply_nterror(req, NT_STATUS_NO_MEMORY);
4101 return;
4103 params = *pparams;
4104 SSVAL(params,0,0);
4105 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
4106 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
4107 if (*ppdata == NULL ) {
4108 reply_nterror(req, NT_STATUS_NO_MEMORY);
4109 return;
4111 pdata = *ppdata;
4113 switch (info_level) {
4114 case SMB_FILE_STANDARD_INFORMATION:
4115 memset(pdata,0,24);
4116 SOFF_T(pdata,0,4096LL);
4117 SIVAL(pdata,16,1);
4118 SIVAL(pdata,20,1);
4119 data_size = 24;
4120 break;
4122 default:
4123 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4124 return;
4127 send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
4128 max_data_bytes);
4130 return;
4133 NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
4134 TALLOC_CTX *mem_ctx,
4135 uint16_t info_level,
4136 files_struct *fsp,
4137 struct smb_filename *smb_fname,
4138 bool delete_pending,
4139 struct timespec write_time_ts,
4140 bool ms_dfs_link,
4141 struct ea_list *ea_list,
4142 int lock_data_count,
4143 char *lock_data,
4144 uint16_t flags2,
4145 unsigned int max_data_bytes,
4146 char **ppdata,
4147 unsigned int *pdata_size)
4149 char *pdata = *ppdata;
4150 char *dstart, *dend;
4151 unsigned int data_size;
4152 struct timespec create_time_ts, mtime_ts, atime_ts, ctime_ts;
4153 time_t create_time, mtime, atime, c_time;
4154 SMB_STRUCT_STAT *psbuf = &smb_fname->st;
4155 char *p;
4156 char *base_name;
4157 char *dos_fname;
4158 int mode;
4159 int nlink;
4160 NTSTATUS status;
4161 uint64_t file_size = 0;
4162 uint64_t pos = 0;
4163 uint64_t allocation_size = 0;
4164 uint64_t file_index = 0;
4165 uint32_t access_mask = 0;
4167 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
4168 return NT_STATUS_INVALID_LEVEL;
4171 DEBUG(5,("smbd_do_qfilepathinfo: %s (fnum = %d) level=%d max_data=%u\n",
4172 smb_fname_str_dbg(smb_fname), fsp ? fsp->fnum : -1,
4173 info_level, max_data_bytes));
4175 if (ms_dfs_link) {
4176 mode = dos_mode_msdfs(conn, smb_fname);
4177 } else {
4178 mode = dos_mode(conn, smb_fname);
4180 if (!mode)
4181 mode = FILE_ATTRIBUTE_NORMAL;
4183 nlink = psbuf->st_ex_nlink;
4185 if (nlink && (mode&aDIR)) {
4186 nlink = 1;
4189 if ((nlink > 0) && delete_pending) {
4190 nlink -= 1;
4193 data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
4194 *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
4195 if (*ppdata == NULL) {
4196 return NT_STATUS_NO_MEMORY;
4198 pdata = *ppdata;
4199 dstart = pdata;
4200 dend = dstart + data_size - 1;
4202 if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) {
4203 update_stat_ex_mtime(psbuf, write_time_ts);
4206 create_time_ts = get_create_timespec(conn, fsp, smb_fname);
4207 mtime_ts = psbuf->st_ex_mtime;
4208 atime_ts = psbuf->st_ex_atime;
4209 ctime_ts = get_change_timespec(conn, fsp, smb_fname);
4211 if (lp_dos_filetime_resolution(SNUM(conn))) {
4212 dos_filetime_timespec(&create_time_ts);
4213 dos_filetime_timespec(&mtime_ts);
4214 dos_filetime_timespec(&atime_ts);
4215 dos_filetime_timespec(&ctime_ts);
4218 create_time = convert_timespec_to_time_t(create_time_ts);
4219 mtime = convert_timespec_to_time_t(mtime_ts);
4220 atime = convert_timespec_to_time_t(atime_ts);
4221 c_time = convert_timespec_to_time_t(ctime_ts);
4223 p = strrchr_m(smb_fname->base_name,'/');
4224 if (!p)
4225 base_name = smb_fname->base_name;
4226 else
4227 base_name = p+1;
4229 /* NT expects the name to be in an exact form of the *full*
4230 filename. See the trans2 torture test */
4231 if (ISDOT(base_name)) {
4232 dos_fname = talloc_strdup(mem_ctx, "\\");
4233 if (!dos_fname) {
4234 return NT_STATUS_NO_MEMORY;
4236 } else {
4237 dos_fname = talloc_asprintf(mem_ctx,
4238 "\\%s",
4239 smb_fname->base_name);
4240 if (!dos_fname) {
4241 return NT_STATUS_NO_MEMORY;
4243 if (is_ntfs_stream_smb_fname(smb_fname)) {
4244 dos_fname = talloc_asprintf(dos_fname, "%s",
4245 smb_fname->stream_name);
4246 if (!dos_fname) {
4247 return NT_STATUS_NO_MEMORY;
4251 string_replace(dos_fname, '/', '\\');
4254 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, psbuf);
4256 if (!fsp) {
4257 /* Do we have this path open ? */
4258 files_struct *fsp1;
4259 struct file_id fileid = vfs_file_id_from_sbuf(conn, psbuf);
4260 fsp1 = file_find_di_first(fileid);
4261 if (fsp1 && fsp1->initial_allocation_size) {
4262 allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, psbuf);
4266 if (!(mode & aDIR)) {
4267 file_size = get_file_size_stat(psbuf);
4270 if (fsp) {
4271 pos = fsp->fh->position_information;
4274 if (fsp) {
4275 access_mask = fsp->access_mask;
4276 } else {
4277 /* GENERIC_EXECUTE mapping from Windows */
4278 access_mask = 0x12019F;
4281 /* This should be an index number - looks like
4282 dev/ino to me :-)
4284 I think this causes us to fail the IFSKIT
4285 BasicFileInformationTest. -tpot */
4286 file_index = ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */
4287 file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */
4289 switch (info_level) {
4290 case SMB_INFO_STANDARD:
4291 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
4292 data_size = 22;
4293 srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
4294 srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
4295 srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
4296 SIVAL(pdata,l1_cbFile,(uint32)file_size);
4297 SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
4298 SSVAL(pdata,l1_attrFile,mode);
4299 break;
4301 case SMB_INFO_QUERY_EA_SIZE:
4303 unsigned int ea_size =
4304 estimate_ea_size(conn, fsp,
4305 smb_fname->base_name);
4306 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
4307 data_size = 26;
4308 srv_put_dos_date2(pdata,0,create_time);
4309 srv_put_dos_date2(pdata,4,atime);
4310 srv_put_dos_date2(pdata,8,mtime); /* write time */
4311 SIVAL(pdata,12,(uint32)file_size);
4312 SIVAL(pdata,16,(uint32)allocation_size);
4313 SSVAL(pdata,20,mode);
4314 SIVAL(pdata,22,ea_size);
4315 break;
4318 case SMB_INFO_IS_NAME_VALID:
4319 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
4320 if (fsp) {
4321 /* os/2 needs this ? really ?*/
4322 return NT_STATUS_DOS(ERRDOS, ERRbadfunc);
4324 /* This is only reached for qpathinfo */
4325 data_size = 0;
4326 break;
4328 case SMB_INFO_QUERY_EAS_FROM_LIST:
4330 size_t total_ea_len = 0;
4331 struct ea_list *ea_file_list = NULL;
4333 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
4335 ea_file_list =
4336 get_ea_list_from_file(mem_ctx, conn, fsp,
4337 smb_fname->base_name,
4338 &total_ea_len);
4339 ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
4341 if (!ea_list || (total_ea_len > data_size)) {
4342 data_size = 4;
4343 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
4344 break;
4347 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
4348 break;
4351 case SMB_INFO_QUERY_ALL_EAS:
4353 /* We have data_size bytes to put EA's into. */
4354 size_t total_ea_len = 0;
4356 DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
4358 ea_list = get_ea_list_from_file(mem_ctx, conn, fsp,
4359 smb_fname->base_name,
4360 &total_ea_len);
4361 if (!ea_list || (total_ea_len > data_size)) {
4362 data_size = 4;
4363 SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
4364 break;
4367 data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
4368 break;
4371 case 0xFF0F:/*SMB2_INFO_QUERY_ALL_EAS*/
4373 /* We have data_size bytes to put EA's into. */
4374 size_t total_ea_len = 0;
4375 struct ea_list *ea_file_list = NULL;
4377 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n"));
4379 /*TODO: add filtering and index handling */
4381 ea_file_list =
4382 get_ea_list_from_file(mem_ctx, conn, fsp,
4383 smb_fname->base_name,
4384 &total_ea_len);
4385 if (!ea_file_list) {
4386 return NT_STATUS_NO_EAS_ON_FILE;
4389 status = fill_ea_chained_buffer(mem_ctx,
4390 pdata,
4391 data_size,
4392 &data_size,
4393 conn, ea_file_list);
4394 if (!NT_STATUS_IS_OK(status)) {
4395 return status;
4397 break;
4400 case SMB_FILE_BASIC_INFORMATION:
4401 case SMB_QUERY_FILE_BASIC_INFO:
4403 if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
4404 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
4405 data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
4406 } else {
4407 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
4408 data_size = 40;
4409 SIVAL(pdata,36,0);
4411 put_long_date_timespec(pdata,create_time_ts);
4412 put_long_date_timespec(pdata+8,atime_ts);
4413 put_long_date_timespec(pdata+16,mtime_ts); /* write time */
4414 put_long_date_timespec(pdata+24,ctime_ts); /* change time */
4415 SIVAL(pdata,32,mode);
4417 DEBUG(5,("SMB_QFBI - "));
4418 DEBUG(5,("create: %s ", ctime(&create_time)));
4419 DEBUG(5,("access: %s ", ctime(&atime)));
4420 DEBUG(5,("write: %s ", ctime(&mtime)));
4421 DEBUG(5,("change: %s ", ctime(&c_time)));
4422 DEBUG(5,("mode: %x\n", mode));
4423 break;
4425 case SMB_FILE_STANDARD_INFORMATION:
4426 case SMB_QUERY_FILE_STANDARD_INFO:
4428 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
4429 data_size = 24;
4430 SOFF_T(pdata,0,allocation_size);
4431 SOFF_T(pdata,8,file_size);
4432 SIVAL(pdata,16,nlink);
4433 SCVAL(pdata,20,delete_pending?1:0);
4434 SCVAL(pdata,21,(mode&aDIR)?1:0);
4435 SSVAL(pdata,22,0); /* Padding. */
4436 break;
4438 case SMB_FILE_EA_INFORMATION:
4439 case SMB_QUERY_FILE_EA_INFO:
4441 unsigned int ea_size =
4442 estimate_ea_size(conn, fsp, smb_fname->base_name);
4443 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
4444 data_size = 4;
4445 SIVAL(pdata,0,ea_size);
4446 break;
4449 /* Get the 8.3 name - used if NT SMB was negotiated. */
4450 case SMB_QUERY_FILE_ALT_NAME_INFO:
4451 case SMB_FILE_ALTERNATE_NAME_INFORMATION:
4453 int len;
4454 char mangled_name[13];
4455 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
4456 if (!name_to_8_3(base_name,mangled_name,
4457 True,conn->params)) {
4458 return NT_STATUS_NO_MEMORY;
4460 len = srvstr_push(dstart, flags2,
4461 pdata+4, mangled_name,
4462 PTR_DIFF(dend, pdata+4),
4463 STR_UNICODE);
4464 data_size = 4 + len;
4465 SIVAL(pdata,0,len);
4466 break;
4469 case SMB_QUERY_FILE_NAME_INFO:
4471 int len;
4473 this must be *exactly* right for ACLs on mapped drives to work
4475 len = srvstr_push(dstart, flags2,
4476 pdata+4, dos_fname,
4477 PTR_DIFF(dend, pdata+4),
4478 STR_UNICODE);
4479 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
4480 data_size = 4 + len;
4481 SIVAL(pdata,0,len);
4482 break;
4485 case SMB_FILE_ALLOCATION_INFORMATION:
4486 case SMB_QUERY_FILE_ALLOCATION_INFO:
4487 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
4488 data_size = 8;
4489 SOFF_T(pdata,0,allocation_size);
4490 break;
4492 case SMB_FILE_END_OF_FILE_INFORMATION:
4493 case SMB_QUERY_FILE_END_OF_FILEINFO:
4494 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
4495 data_size = 8;
4496 SOFF_T(pdata,0,file_size);
4497 break;
4499 case SMB_QUERY_FILE_ALL_INFO:
4500 case SMB_FILE_ALL_INFORMATION:
4502 int len;
4503 unsigned int ea_size =
4504 estimate_ea_size(conn, fsp, smb_fname->base_name);
4505 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
4506 put_long_date_timespec(pdata,create_time_ts);
4507 put_long_date_timespec(pdata+8,atime_ts);
4508 put_long_date_timespec(pdata+16,mtime_ts); /* write time */
4509 put_long_date_timespec(pdata+24,ctime_ts); /* change time */
4510 SIVAL(pdata,32,mode);
4511 SIVAL(pdata,36,0); /* padding. */
4512 pdata += 40;
4513 SOFF_T(pdata,0,allocation_size);
4514 SOFF_T(pdata,8,file_size);
4515 SIVAL(pdata,16,nlink);
4516 SCVAL(pdata,20,delete_pending);
4517 SCVAL(pdata,21,(mode&aDIR)?1:0);
4518 SSVAL(pdata,22,0);
4519 pdata += 24;
4520 SIVAL(pdata,0,ea_size);
4521 pdata += 4; /* EA info */
4522 len = srvstr_push(dstart, flags2,
4523 pdata+4, dos_fname,
4524 PTR_DIFF(dend, pdata+4),
4525 STR_UNICODE);
4526 SIVAL(pdata,0,len);
4527 pdata += 4 + len;
4528 data_size = PTR_DIFF(pdata,(*ppdata));
4529 break;
4532 case 0xFF12:/*SMB2_FILE_ALL_INFORMATION*/
4534 int len;
4535 unsigned int ea_size =
4536 estimate_ea_size(conn, fsp, smb_fname->base_name);
4537 DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
4538 put_long_date_timespec(pdata+0x00,create_time_ts);
4539 put_long_date_timespec(pdata+0x08,atime_ts);
4540 put_long_date_timespec(pdata+0x10,mtime_ts); /* write time */
4541 put_long_date_timespec(pdata+0x18,ctime_ts); /* change time */
4542 SIVAL(pdata, 0x20, mode);
4543 SIVAL(pdata, 0x24, 0); /* padding. */
4544 SBVAL(pdata, 0x28, allocation_size);
4545 SBVAL(pdata, 0x30, file_size);
4546 SIVAL(pdata, 0x38, nlink);
4547 SCVAL(pdata, 0x3C, delete_pending);
4548 SCVAL(pdata, 0x3D, (mode&aDIR)?1:0);
4549 SSVAL(pdata, 0x3E, 0); /* padding */
4550 SBVAL(pdata, 0x40, file_index);
4551 SIVAL(pdata, 0x48, ea_size);
4552 SIVAL(pdata, 0x4C, access_mask);
4553 SBVAL(pdata, 0x50, pos);
4554 SIVAL(pdata, 0x58, mode); /*TODO: mode != mode fix this!!! */
4555 SIVAL(pdata, 0x5C, 0); /* No alignment needed. */
4557 pdata += 0x60;
4559 len = srvstr_push(dstart, flags2,
4560 pdata+4, dos_fname,
4561 PTR_DIFF(dend, pdata+4),
4562 STR_UNICODE);
4563 SIVAL(pdata,0,len);
4564 pdata += 4 + len;
4565 data_size = PTR_DIFF(pdata,(*ppdata));
4566 break;
4568 case SMB_FILE_INTERNAL_INFORMATION:
4570 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
4571 SBVAL(pdata, 0, file_index);
4572 data_size = 8;
4573 break;
4575 case SMB_FILE_ACCESS_INFORMATION:
4576 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
4577 SIVAL(pdata, 0, access_mask);
4578 data_size = 4;
4579 break;
4581 case SMB_FILE_NAME_INFORMATION:
4582 /* Pathname with leading '\'. */
4584 size_t byte_len;
4585 byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
4586 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
4587 SIVAL(pdata,0,byte_len);
4588 data_size = 4 + byte_len;
4589 break;
4592 case SMB_FILE_DISPOSITION_INFORMATION:
4593 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
4594 data_size = 1;
4595 SCVAL(pdata,0,delete_pending);
4596 break;
4598 case SMB_FILE_POSITION_INFORMATION:
4599 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
4600 data_size = 8;
4601 SOFF_T(pdata,0,pos);
4602 break;
4604 case SMB_FILE_MODE_INFORMATION:
4605 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
4606 SIVAL(pdata,0,mode);
4607 data_size = 4;
4608 break;
4610 case SMB_FILE_ALIGNMENT_INFORMATION:
4611 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
4612 SIVAL(pdata,0,0); /* No alignment needed. */
4613 data_size = 4;
4614 break;
4617 * NT4 server just returns "invalid query" to this - if we try
4618 * to answer it then NTws gets a BSOD! (tridge). W2K seems to
4619 * want this. JRA.
4621 /* The first statement above is false - verified using Thursby
4622 * client against NT4 -- gcolley.
4624 case SMB_QUERY_FILE_STREAM_INFO:
4625 case SMB_FILE_STREAM_INFORMATION: {
4626 unsigned int num_streams;
4627 struct stream_struct *streams;
4629 DEBUG(10,("smbd_do_qfilepathinfo: "
4630 "SMB_FILE_STREAM_INFORMATION\n"));
4632 if (is_ntfs_stream_smb_fname(smb_fname)) {
4633 return NT_STATUS_INVALID_PARAMETER;
4636 status = SMB_VFS_STREAMINFO(
4637 conn, fsp, smb_fname->base_name, talloc_tos(),
4638 &num_streams, &streams);
4640 if (!NT_STATUS_IS_OK(status)) {
4641 DEBUG(10, ("could not get stream info: %s\n",
4642 nt_errstr(status)));
4643 return status;
4646 status = marshall_stream_info(num_streams, streams,
4647 pdata, max_data_bytes,
4648 &data_size);
4650 if (!NT_STATUS_IS_OK(status)) {
4651 DEBUG(10, ("marshall_stream_info failed: %s\n",
4652 nt_errstr(status)));
4653 return status;
4656 TALLOC_FREE(streams);
4658 break;
4660 case SMB_QUERY_COMPRESSION_INFO:
4661 case SMB_FILE_COMPRESSION_INFORMATION:
4662 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
4663 SOFF_T(pdata,0,file_size);
4664 SIVAL(pdata,8,0); /* ??? */
4665 SIVAL(pdata,12,0); /* ??? */
4666 data_size = 16;
4667 break;
4669 case SMB_FILE_NETWORK_OPEN_INFORMATION:
4670 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
4671 put_long_date_timespec(pdata,create_time_ts);
4672 put_long_date_timespec(pdata+8,atime_ts);
4673 put_long_date_timespec(pdata+16,mtime_ts); /* write time */
4674 put_long_date_timespec(pdata+24,ctime_ts); /* change time */
4675 SOFF_T(pdata,32,allocation_size);
4676 SOFF_T(pdata,40,file_size);
4677 SIVAL(pdata,48,mode);
4678 SIVAL(pdata,52,0); /* ??? */
4679 data_size = 56;
4680 break;
4682 case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
4683 DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
4684 SIVAL(pdata,0,mode);
4685 SIVAL(pdata,4,0);
4686 data_size = 8;
4687 break;
4690 * CIFS UNIX Extensions.
4693 case SMB_QUERY_FILE_UNIX_BASIC:
4695 pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
4696 data_size = PTR_DIFF(pdata,(*ppdata));
4699 int i;
4700 DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC "));
4702 for (i=0; i<100; i++)
4703 DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
4704 DEBUG(4,("\n"));
4707 break;
4709 case SMB_QUERY_FILE_UNIX_INFO2:
4711 pdata = store_file_unix_basic_info2(conn, pdata, fsp, psbuf);
4712 data_size = PTR_DIFF(pdata,(*ppdata));
4715 int i;
4716 DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));
4718 for (i=0; i<100; i++)
4719 DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
4720 DEBUG(4,("\n"));
4723 break;
4725 case SMB_QUERY_FILE_UNIX_LINK:
4727 int len;
4728 char *buffer = TALLOC_ARRAY(mem_ctx, char, PATH_MAX+1);
4730 if (!buffer) {
4731 return NT_STATUS_NO_MEMORY;
4734 DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n"));
4735 #ifdef S_ISLNK
4736 if(!S_ISLNK(psbuf->st_ex_mode)) {
4737 return NT_STATUS_DOS(ERRSRV, ERRbadlink);
4739 #else
4740 return NT_STATUS_DOS(ERRDOS, ERRbadlink);
4741 #endif
4742 len = SMB_VFS_READLINK(conn,
4743 smb_fname->base_name,
4744 buffer, PATH_MAX);
4745 if (len == -1) {
4746 return map_nt_error_from_unix(errno);
4748 buffer[len] = 0;
4749 len = srvstr_push(dstart, flags2,
4750 pdata, buffer,
4751 PTR_DIFF(dend, pdata),
4752 STR_TERMINATE);
4753 pdata += len;
4754 data_size = PTR_DIFF(pdata,(*ppdata));
4756 break;
4759 #if defined(HAVE_POSIX_ACLS)
4760 case SMB_QUERY_POSIX_ACL:
4762 SMB_ACL_T file_acl = NULL;
4763 SMB_ACL_T def_acl = NULL;
4764 uint16 num_file_acls = 0;
4765 uint16 num_def_acls = 0;
4767 if (fsp && !fsp->is_directory && (fsp->fh->fd != -1)) {
4768 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
4769 } else {
4770 file_acl =
4771 SMB_VFS_SYS_ACL_GET_FILE(conn,
4772 smb_fname->base_name,
4773 SMB_ACL_TYPE_ACCESS);
4776 if (file_acl == NULL && no_acl_syscall_error(errno)) {
4777 DEBUG(5,("smbd_do_qfilepathinfo: ACLs "
4778 "not implemented on "
4779 "filesystem containing %s\n",
4780 smb_fname->base_name));
4781 return NT_STATUS_NOT_IMPLEMENTED;
4784 if (S_ISDIR(psbuf->st_ex_mode)) {
4785 if (fsp && fsp->is_directory) {
4786 def_acl =
4787 SMB_VFS_SYS_ACL_GET_FILE(
4788 conn,
4789 fsp->fsp_name->base_name,
4790 SMB_ACL_TYPE_DEFAULT);
4791 } else {
4792 def_acl =
4793 SMB_VFS_SYS_ACL_GET_FILE(
4794 conn,
4795 smb_fname->base_name,
4796 SMB_ACL_TYPE_DEFAULT);
4798 def_acl = free_empty_sys_acl(conn, def_acl);
4801 num_file_acls = count_acl_entries(conn, file_acl);
4802 num_def_acls = count_acl_entries(conn, def_acl);
4804 if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) {
4805 DEBUG(5,("smbd_do_qfilepathinfo: data_size too small (%u) need %u\n",
4806 data_size,
4807 (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
4808 SMB_POSIX_ACL_HEADER_SIZE) ));
4809 if (file_acl) {
4810 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4812 if (def_acl) {
4813 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4815 return NT_STATUS_BUFFER_TOO_SMALL;
4818 SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
4819 SSVAL(pdata,2,num_file_acls);
4820 SSVAL(pdata,4,num_def_acls);
4821 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, psbuf, file_acl)) {
4822 if (file_acl) {
4823 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4825 if (def_acl) {
4826 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4828 return NT_STATUS_INTERNAL_ERROR;
4830 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), psbuf, def_acl)) {
4831 if (file_acl) {
4832 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4834 if (def_acl) {
4835 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4837 return NT_STATUS_INTERNAL_ERROR;
4840 if (file_acl) {
4841 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4843 if (def_acl) {
4844 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4846 data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
4847 break;
4849 #endif
4852 case SMB_QUERY_POSIX_LOCK:
4854 uint64_t count;
4855 uint64_t offset;
4856 uint32 lock_pid;
4857 enum brl_type lock_type;
4859 /* We need an open file with a real fd for this. */
4860 if (!fsp || fsp->is_directory || fsp->fh->fd == -1) {
4861 return NT_STATUS_INVALID_LEVEL;
4864 if (lock_data_count != POSIX_LOCK_DATA_SIZE) {
4865 return NT_STATUS_INVALID_PARAMETER;
4868 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
4869 case POSIX_LOCK_TYPE_READ:
4870 lock_type = READ_LOCK;
4871 break;
4872 case POSIX_LOCK_TYPE_WRITE:
4873 lock_type = WRITE_LOCK;
4874 break;
4875 case POSIX_LOCK_TYPE_UNLOCK:
4876 default:
4877 /* There's no point in asking for an unlock... */
4878 return NT_STATUS_INVALID_PARAMETER;
4881 lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
4882 #if defined(HAVE_LONGLONG)
4883 offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
4884 ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
4885 count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
4886 ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
4887 #else /* HAVE_LONGLONG */
4888 offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET);
4889 count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
4890 #endif /* HAVE_LONGLONG */
4892 status = query_lock(fsp,
4893 &lock_pid,
4894 &count,
4895 &offset,
4896 &lock_type,
4897 POSIX_LOCK);
4899 if (ERROR_WAS_LOCK_DENIED(status)) {
4900 /* Here we need to report who has it locked... */
4901 data_size = POSIX_LOCK_DATA_SIZE;
4903 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
4904 SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
4905 SIVAL(pdata, POSIX_LOCK_PID_OFFSET, lock_pid);
4906 #if defined(HAVE_LONGLONG)
4907 SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF));
4908 SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF));
4909 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF));
4910 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF));
4911 #else /* HAVE_LONGLONG */
4912 SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
4913 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
4914 #endif /* HAVE_LONGLONG */
4916 } else if (NT_STATUS_IS_OK(status)) {
4917 /* For success we just return a copy of what we sent
4918 with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
4919 data_size = POSIX_LOCK_DATA_SIZE;
4920 memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
4921 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
4922 } else {
4923 return status;
4925 break;
4928 default:
4929 return NT_STATUS_INVALID_LEVEL;
4932 *pdata_size = data_size;
4933 return NT_STATUS_OK;
4936 /****************************************************************************
4937 Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
4938 file name or file id).
4939 ****************************************************************************/
4941 static void call_trans2qfilepathinfo(connection_struct *conn,
4942 struct smb_request *req,
4943 unsigned int tran_call,
4944 char **pparams, int total_params,
4945 char **ppdata, int total_data,
4946 unsigned int max_data_bytes)
4948 char *params = *pparams;
4949 char *pdata = *ppdata;
4950 uint16 info_level;
4951 unsigned int data_size = 0;
4952 unsigned int param_size = 2;
4953 struct smb_filename *smb_fname = NULL;
4954 bool delete_pending = False;
4955 struct timespec write_time_ts;
4956 files_struct *fsp = NULL;
4957 struct file_id fileid;
4958 struct ea_list *ea_list = NULL;
4959 int lock_data_count = 0;
4960 char *lock_data = NULL;
4961 bool ms_dfs_link = false;
4962 NTSTATUS status = NT_STATUS_OK;
4964 if (!params) {
4965 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4966 return;
4969 ZERO_STRUCT(write_time_ts);
4971 if (tran_call == TRANSACT2_QFILEINFO) {
4972 if (total_params < 4) {
4973 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4974 return;
4977 if (IS_IPC(conn)) {
4978 call_trans2qpipeinfo(conn, req, tran_call,
4979 pparams, total_params,
4980 ppdata, total_data,
4981 max_data_bytes);
4982 return;
4985 fsp = file_fsp(req, SVAL(params,0));
4986 info_level = SVAL(params,2);
4988 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
4990 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
4991 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
4992 return;
4995 /* Initial check for valid fsp ptr. */
4996 if (!check_fsp_open(conn, req, fsp)) {
4997 return;
5000 status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
5001 &smb_fname);
5002 if (!NT_STATUS_IS_OK(status)) {
5003 reply_nterror(req, status);
5004 return;
5007 if(fsp->fake_file_handle) {
5009 * This is actually for the QUOTA_FAKE_FILE --metze
5012 /* We know this name is ok, it's already passed the checks. */
5014 } else if(fsp->is_directory || fsp->fh->fd == -1) {
5016 * This is actually a QFILEINFO on a directory
5017 * handle (returned from an NT SMB). NT5.0 seems
5018 * to do this call. JRA.
5021 if (INFO_LEVEL_IS_UNIX(info_level)) {
5022 /* Always do lstat for UNIX calls. */
5023 if (SMB_VFS_LSTAT(conn, smb_fname)) {
5024 DEBUG(3,("call_trans2qfilepathinfo: "
5025 "SMB_VFS_LSTAT of %s failed "
5026 "(%s)\n",
5027 smb_fname_str_dbg(smb_fname),
5028 strerror(errno)));
5029 reply_nterror(req,
5030 map_nt_error_from_unix(errno));
5031 return;
5033 } else if (SMB_VFS_STAT(conn, smb_fname)) {
5034 DEBUG(3,("call_trans2qfilepathinfo: "
5035 "SMB_VFS_STAT of %s failed (%s)\n",
5036 smb_fname_str_dbg(smb_fname),
5037 strerror(errno)));
5038 reply_nterror(req,
5039 map_nt_error_from_unix(errno));
5040 return;
5043 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5044 get_file_infos(fileid, &delete_pending, &write_time_ts);
5045 } else {
5047 * Original code - this is an open file.
5049 if (!check_fsp(conn, req, fsp)) {
5050 return;
5053 if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
5054 DEBUG(3, ("fstat of fnum %d failed (%s)\n",
5055 fsp->fnum, strerror(errno)));
5056 reply_nterror(req,
5057 map_nt_error_from_unix(errno));
5058 return;
5060 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5061 get_file_infos(fileid, &delete_pending, &write_time_ts);
5064 } else {
5065 char *fname = NULL;
5067 /* qpathinfo */
5068 if (total_params < 7) {
5069 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5070 return;
5073 info_level = SVAL(params,0);
5075 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
5077 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
5078 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5079 return;
5082 srvstr_get_path(req, params, req->flags2, &fname, &params[6],
5083 total_params - 6,
5084 STR_TERMINATE, &status);
5085 if (!NT_STATUS_IS_OK(status)) {
5086 reply_nterror(req, status);
5087 return;
5090 status = filename_convert(req,
5091 conn,
5092 req->flags2 & FLAGS2_DFS_PATHNAMES,
5093 fname,
5095 NULL,
5096 &smb_fname);
5097 if (!NT_STATUS_IS_OK(status)) {
5098 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5099 reply_botherror(req,
5100 NT_STATUS_PATH_NOT_COVERED,
5101 ERRSRV, ERRbadpath);
5102 return;
5104 reply_nterror(req, status);
5105 return;
5108 /* If this is a stream, check if there is a delete_pending. */
5109 if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
5110 && is_ntfs_stream_smb_fname(smb_fname)) {
5111 struct smb_filename *smb_fname_base = NULL;
5113 /* Create an smb_filename with stream_name == NULL. */
5114 status =
5115 create_synthetic_smb_fname(talloc_tos(),
5116 smb_fname->base_name,
5117 NULL, NULL,
5118 &smb_fname_base);
5119 if (!NT_STATUS_IS_OK(status)) {
5120 reply_nterror(req, status);
5121 return;
5124 if (INFO_LEVEL_IS_UNIX(info_level)) {
5125 /* Always do lstat for UNIX calls. */
5126 if (SMB_VFS_LSTAT(conn, smb_fname_base) != 0) {
5127 DEBUG(3,("call_trans2qfilepathinfo: "
5128 "SMB_VFS_LSTAT of %s failed "
5129 "(%s)\n",
5130 smb_fname_str_dbg(smb_fname_base),
5131 strerror(errno)));
5132 TALLOC_FREE(smb_fname_base);
5133 reply_nterror(req,
5134 map_nt_error_from_unix(errno));
5135 return;
5137 } else {
5138 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
5139 DEBUG(3,("call_trans2qfilepathinfo: "
5140 "fileinfo of %s failed "
5141 "(%s)\n",
5142 smb_fname_str_dbg(smb_fname_base),
5143 strerror(errno)));
5144 TALLOC_FREE(smb_fname_base);
5145 reply_nterror(req,
5146 map_nt_error_from_unix(errno));
5147 return;
5151 fileid = vfs_file_id_from_sbuf(conn,
5152 &smb_fname_base->st);
5153 TALLOC_FREE(smb_fname_base);
5154 get_file_infos(fileid, &delete_pending, NULL);
5155 if (delete_pending) {
5156 reply_nterror(req, NT_STATUS_DELETE_PENDING);
5157 return;
5161 if (INFO_LEVEL_IS_UNIX(info_level)) {
5162 /* Always do lstat for UNIX calls. */
5163 if (SMB_VFS_LSTAT(conn, smb_fname)) {
5164 DEBUG(3,("call_trans2qfilepathinfo: "
5165 "SMB_VFS_LSTAT of %s failed (%s)\n",
5166 smb_fname_str_dbg(smb_fname),
5167 strerror(errno)));
5168 reply_nterror(req,
5169 map_nt_error_from_unix(errno));
5170 return;
5173 } else if (!VALID_STAT(smb_fname->st) &&
5174 SMB_VFS_STAT(conn, smb_fname) &&
5175 (info_level != SMB_INFO_IS_NAME_VALID)) {
5176 ms_dfs_link = check_msdfs_link(conn,
5177 smb_fname->base_name,
5178 &smb_fname->st);
5180 if (!ms_dfs_link) {
5181 DEBUG(3,("call_trans2qfilepathinfo: "
5182 "SMB_VFS_STAT of %s failed (%s)\n",
5183 smb_fname_str_dbg(smb_fname),
5184 strerror(errno)));
5185 reply_nterror(req,
5186 map_nt_error_from_unix(errno));
5187 return;
5191 fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
5192 get_file_infos(fileid, &delete_pending, &write_time_ts);
5193 if (delete_pending) {
5194 reply_nterror(req, NT_STATUS_DELETE_PENDING);
5195 return;
5199 DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d "
5200 "total_data=%d\n", smb_fname_str_dbg(smb_fname),
5201 fsp ? fsp->fnum : -1, info_level,tran_call,total_data));
5203 /* Pull out any data sent here before we realloc. */
5204 switch (info_level) {
5205 case SMB_INFO_QUERY_EAS_FROM_LIST:
5207 /* Pull any EA list from the data portion. */
5208 uint32 ea_size;
5210 if (total_data < 4) {
5211 reply_nterror(
5212 req, NT_STATUS_INVALID_PARAMETER);
5213 return;
5215 ea_size = IVAL(pdata,0);
5217 if (total_data > 0 && ea_size != total_data) {
5218 DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
5219 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
5220 reply_nterror(
5221 req, NT_STATUS_INVALID_PARAMETER);
5222 return;
5225 if (!lp_ea_support(SNUM(conn))) {
5226 reply_doserror(req, ERRDOS,
5227 ERReasnotsupported);
5228 return;
5231 /* Pull out the list of names. */
5232 ea_list = read_ea_name_list(req, pdata + 4, ea_size - 4);
5233 if (!ea_list) {
5234 reply_nterror(
5235 req, NT_STATUS_INVALID_PARAMETER);
5236 return;
5238 break;
5241 case SMB_QUERY_POSIX_LOCK:
5243 if (fsp == NULL || fsp->fh->fd == -1) {
5244 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
5245 return;
5248 if (total_data != POSIX_LOCK_DATA_SIZE) {
5249 reply_nterror(
5250 req, NT_STATUS_INVALID_PARAMETER);
5251 return;
5254 /* Copy the lock range data. */
5255 lock_data = (char *)TALLOC_MEMDUP(
5256 req, pdata, total_data);
5257 if (!lock_data) {
5258 reply_nterror(req, NT_STATUS_NO_MEMORY);
5259 return;
5261 lock_data_count = total_data;
5263 default:
5264 break;
5267 *pparams = (char *)SMB_REALLOC(*pparams,2);
5268 if (*pparams == NULL) {
5269 reply_nterror(req, NT_STATUS_NO_MEMORY);
5270 return;
5272 params = *pparams;
5273 SSVAL(params,0,0);
5276 * draft-leach-cifs-v1-spec-02.txt
5277 * 4.2.14 TRANS2_QUERY_PATH_INFORMATION: Get File Attributes given Path
5278 * says:
5280 * The requested information is placed in the Data portion of the
5281 * transaction response. For the information levels greater than 0x100,
5282 * the transaction response has 1 parameter word which should be
5283 * ignored by the client.
5285 * However Windows only follows this rule for the IS_NAME_VALID call.
5287 switch (info_level) {
5288 case SMB_INFO_IS_NAME_VALID:
5289 param_size = 0;
5290 break;
5293 if ((info_level & 0xFF00) == 0xFF00) {
5295 * We use levels that start with 0xFF00
5296 * internally to represent SMB2 specific levels
5298 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
5299 return;
5302 status = smbd_do_qfilepathinfo(conn, req, info_level,
5303 fsp, smb_fname,
5304 delete_pending, write_time_ts,
5305 ms_dfs_link, ea_list,
5306 lock_data_count, lock_data,
5307 req->flags2, max_data_bytes,
5308 ppdata, &data_size);
5309 if (!NT_STATUS_IS_OK(status)) {
5310 reply_nterror(req, status);
5311 return;
5314 send_trans2_replies(conn, req, params, param_size, *ppdata, data_size,
5315 max_data_bytes);
5317 return;
5320 /****************************************************************************
5321 Set a hard link (called by UNIX extensions and by NT rename with HARD link
5322 code.
5323 ****************************************************************************/
5325 NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
5326 connection_struct *conn,
5327 const struct smb_filename *smb_fname_old,
5328 const struct smb_filename *smb_fname_new)
5330 NTSTATUS status = NT_STATUS_OK;
5332 /* source must already exist. */
5333 if (!VALID_STAT(smb_fname_old->st)) {
5334 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5337 /* Disallow if newname already exists. */
5338 if (VALID_STAT(smb_fname_new->st)) {
5339 return NT_STATUS_OBJECT_NAME_COLLISION;
5342 /* No links from a directory. */
5343 if (S_ISDIR(smb_fname_old->st.st_ex_mode)) {
5344 return NT_STATUS_FILE_IS_A_DIRECTORY;
5347 /* Setting a hardlink to/from a stream isn't currently supported. */
5348 if (is_ntfs_stream_smb_fname(smb_fname_old) ||
5349 is_ntfs_stream_smb_fname(smb_fname_new)) {
5350 return NT_STATUS_INVALID_PARAMETER;
5353 DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n",
5354 smb_fname_old->base_name, smb_fname_new->base_name));
5356 if (SMB_VFS_LINK(conn, smb_fname_old->base_name,
5357 smb_fname_new->base_name) != 0) {
5358 status = map_nt_error_from_unix(errno);
5359 DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
5360 nt_errstr(status), smb_fname_old->base_name,
5361 smb_fname_new->base_name));
5363 return status;
5366 /****************************************************************************
5367 Deal with setting the time from any of the setfilepathinfo functions.
5368 ****************************************************************************/
5370 NTSTATUS smb_set_file_time(connection_struct *conn,
5371 files_struct *fsp,
5372 const struct smb_filename *smb_fname,
5373 struct smb_file_time *ft,
5374 bool setting_write_time)
5376 struct smb_filename *smb_fname_base = NULL;
5377 uint32 action =
5378 FILE_NOTIFY_CHANGE_LAST_ACCESS
5379 |FILE_NOTIFY_CHANGE_LAST_WRITE
5380 |FILE_NOTIFY_CHANGE_CREATION;
5381 NTSTATUS status;
5383 if (!VALID_STAT(smb_fname->st)) {
5384 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5387 /* get some defaults (no modifications) if any info is zero or -1. */
5388 if (null_timespec(ft->create_time)) {
5389 action &= ~FILE_NOTIFY_CHANGE_CREATION;
5392 if (null_timespec(ft->atime)) {
5393 action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
5396 if (null_timespec(ft->mtime)) {
5397 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
5400 if (!setting_write_time) {
5401 /* ft->mtime comes from change time, not write time. */
5402 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
5405 DEBUG(5,("smb_set_filetime: actime: %s\n ",
5406 time_to_asc(convert_timespec_to_time_t(ft->atime))));
5407 DEBUG(5,("smb_set_filetime: modtime: %s\n ",
5408 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
5409 DEBUG(5,("smb_set_filetime: ctime: %s\n ",
5410 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
5411 DEBUG(5,("smb_set_file_time: createtime: %s\n ",
5412 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
5414 if (setting_write_time) {
5416 * This was a Windows setfileinfo on an open file.
5417 * NT does this a lot. We also need to
5418 * set the time here, as it can be read by
5419 * FindFirst/FindNext and with the patch for bug #2045
5420 * in smbd/fileio.c it ensures that this timestamp is
5421 * kept sticky even after a write. We save the request
5422 * away and will set it on file close and after a write. JRA.
5425 DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n",
5426 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
5428 if (fsp != NULL) {
5429 if (fsp->base_fsp) {
5430 set_sticky_write_time_fsp(fsp->base_fsp,
5431 ft->mtime);
5432 } else {
5433 set_sticky_write_time_fsp(fsp, ft->mtime);
5435 } else {
5436 set_sticky_write_time_path(
5437 vfs_file_id_from_sbuf(conn, &smb_fname->st),
5438 ft->mtime);
5442 DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
5444 /* Always call ntimes on the base, even if a stream was passed in. */
5445 status = create_synthetic_smb_fname(talloc_tos(), smb_fname->base_name,
5446 NULL, &smb_fname->st,
5447 &smb_fname_base);
5448 if (!NT_STATUS_IS_OK(status)) {
5449 return status;
5452 if(file_ntimes(conn, smb_fname_base, ft)!=0) {
5453 TALLOC_FREE(smb_fname_base);
5454 return map_nt_error_from_unix(errno);
5456 TALLOC_FREE(smb_fname_base);
5458 notify_fname(conn, NOTIFY_ACTION_MODIFIED, action,
5459 smb_fname->base_name);
5460 return NT_STATUS_OK;
5463 /****************************************************************************
5464 Deal with setting the dosmode from any of the setfilepathinfo functions.
5465 ****************************************************************************/
5467 static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
5468 const struct smb_filename *smb_fname,
5469 uint32 dosmode)
5471 struct smb_filename *smb_fname_base = NULL;
5472 NTSTATUS status;
5474 if (!VALID_STAT(smb_fname->st)) {
5475 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5478 /* Always operate on the base_name, even if a stream was passed in. */
5479 status = create_synthetic_smb_fname(talloc_tos(), smb_fname->base_name,
5480 NULL, &smb_fname->st,
5481 &smb_fname_base);
5482 if (!NT_STATUS_IS_OK(status)) {
5483 return status;
5486 if (dosmode) {
5487 if (S_ISDIR(smb_fname_base->st.st_ex_mode)) {
5488 dosmode |= aDIR;
5489 } else {
5490 dosmode &= ~aDIR;
5494 DEBUG(6,("smb_set_file_dosmode: dosmode: 0x%x\n", (unsigned int)dosmode));
5496 /* check the mode isn't different, before changing it */
5497 if ((dosmode != 0) && (dosmode != dos_mode(conn, smb_fname_base))) {
5498 DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode "
5499 "0x%x\n", smb_fname_str_dbg(smb_fname_base),
5500 (unsigned int)dosmode));
5502 if(file_set_dosmode(conn, smb_fname_base, dosmode, NULL,
5503 false)) {
5504 DEBUG(2,("smb_set_file_dosmode: file_set_dosmode of "
5505 "%s failed (%s)\n",
5506 smb_fname_str_dbg(smb_fname_base),
5507 strerror(errno)));
5508 status = map_nt_error_from_unix(errno);
5509 goto out;
5512 status = NT_STATUS_OK;
5513 out:
5514 TALLOC_FREE(smb_fname_base);
5515 return status;
5518 /****************************************************************************
5519 Deal with setting the size from any of the setfilepathinfo functions.
5520 ****************************************************************************/
5522 static NTSTATUS smb_set_file_size(connection_struct *conn,
5523 struct smb_request *req,
5524 files_struct *fsp,
5525 const struct smb_filename *smb_fname,
5526 const SMB_STRUCT_STAT *psbuf,
5527 SMB_OFF_T size)
5529 NTSTATUS status = NT_STATUS_OK;
5530 struct smb_filename *smb_fname_tmp = NULL;
5531 files_struct *new_fsp = NULL;
5533 if (!VALID_STAT(*psbuf)) {
5534 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5537 DEBUG(6,("smb_set_file_size: size: %.0f ", (double)size));
5539 if (size == get_file_size_stat(psbuf)) {
5540 return NT_STATUS_OK;
5543 DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n",
5544 smb_fname_str_dbg(smb_fname), (double)size));
5546 if (fsp && fsp->fh->fd != -1) {
5547 /* Handle based call. */
5548 if (vfs_set_filelen(fsp, size) == -1) {
5549 return map_nt_error_from_unix(errno);
5551 trigger_write_time_update_immediate(fsp);
5552 return NT_STATUS_OK;
5555 status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
5556 if (!NT_STATUS_IS_OK(status)) {
5557 return status;
5560 smb_fname_tmp->st = *psbuf;
5562 status = SMB_VFS_CREATE_FILE(
5563 conn, /* conn */
5564 req, /* req */
5565 0, /* root_dir_fid */
5566 smb_fname_tmp, /* fname */
5567 FILE_WRITE_ATTRIBUTES, /* access_mask */
5568 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5569 FILE_SHARE_DELETE),
5570 FILE_OPEN, /* create_disposition*/
5571 0, /* create_options */
5572 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
5573 FORCE_OPLOCK_BREAK_TO_NONE, /* oplock_request */
5574 0, /* allocation_size */
5575 NULL, /* sd */
5576 NULL, /* ea_list */
5577 &new_fsp, /* result */
5578 NULL); /* pinfo */
5580 TALLOC_FREE(smb_fname_tmp);
5582 if (!NT_STATUS_IS_OK(status)) {
5583 /* NB. We check for open_was_deferred in the caller. */
5584 return status;
5587 if (vfs_set_filelen(new_fsp, size) == -1) {
5588 status = map_nt_error_from_unix(errno);
5589 close_file(req, new_fsp,NORMAL_CLOSE);
5590 return status;
5593 trigger_write_time_update_immediate(new_fsp);
5594 close_file(req, new_fsp,NORMAL_CLOSE);
5595 return NT_STATUS_OK;
5598 /****************************************************************************
5599 Deal with SMB_INFO_SET_EA.
5600 ****************************************************************************/
5602 static NTSTATUS smb_info_set_ea(connection_struct *conn,
5603 const char *pdata,
5604 int total_data,
5605 files_struct *fsp,
5606 const struct smb_filename *smb_fname)
5608 struct ea_list *ea_list = NULL;
5609 TALLOC_CTX *ctx = NULL;
5610 NTSTATUS status = NT_STATUS_OK;
5612 if (total_data < 10) {
5614 /* OS/2 workplace shell seems to send SET_EA requests of "null"
5615 length. They seem to have no effect. Bug #3212. JRA */
5617 if ((total_data == 4) && (IVAL(pdata,0) == 4)) {
5618 /* We're done. We only get EA info in this call. */
5619 return NT_STATUS_OK;
5622 return NT_STATUS_INVALID_PARAMETER;
5625 if (IVAL(pdata,0) > total_data) {
5626 DEBUG(10,("smb_info_set_ea: bad total data size (%u) > %u\n",
5627 IVAL(pdata,0), (unsigned int)total_data));
5628 return NT_STATUS_INVALID_PARAMETER;
5631 ctx = talloc_tos();
5632 ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
5633 if (!ea_list) {
5634 return NT_STATUS_INVALID_PARAMETER;
5636 status = set_ea(conn, fsp, smb_fname, ea_list);
5638 return status;
5641 /****************************************************************************
5642 Deal with SMB_SET_FILE_DISPOSITION_INFO.
5643 ****************************************************************************/
5645 static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
5646 const char *pdata,
5647 int total_data,
5648 files_struct *fsp,
5649 const struct smb_filename *smb_fname)
5651 NTSTATUS status = NT_STATUS_OK;
5652 bool delete_on_close;
5653 uint32 dosmode = 0;
5655 if (total_data < 1) {
5656 return NT_STATUS_INVALID_PARAMETER;
5659 if (fsp == NULL) {
5660 return NT_STATUS_INVALID_HANDLE;
5663 delete_on_close = (CVAL(pdata,0) ? True : False);
5664 dosmode = dos_mode(conn, smb_fname);
5666 DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
5667 "delete_on_close = %u\n",
5668 smb_fname_str_dbg(smb_fname),
5669 (unsigned int)dosmode,
5670 (unsigned int)delete_on_close ));
5672 status = can_set_delete_on_close(fsp, delete_on_close, dosmode);
5674 if (!NT_STATUS_IS_OK(status)) {
5675 return status;
5678 /* The set is across all open files on this dev/inode pair. */
5679 if (!set_delete_on_close(fsp, delete_on_close,
5680 &conn->server_info->utok)) {
5681 return NT_STATUS_ACCESS_DENIED;
5683 return NT_STATUS_OK;
5686 /****************************************************************************
5687 Deal with SMB_FILE_POSITION_INFORMATION.
5688 ****************************************************************************/
5690 static NTSTATUS smb_file_position_information(connection_struct *conn,
5691 const char *pdata,
5692 int total_data,
5693 files_struct *fsp)
5695 uint64_t position_information;
5697 if (total_data < 8) {
5698 return NT_STATUS_INVALID_PARAMETER;
5701 if (fsp == NULL) {
5702 /* Ignore on pathname based set. */
5703 return NT_STATUS_OK;
5706 position_information = (uint64_t)IVAL(pdata,0);
5707 #ifdef LARGE_SMB_OFF_T
5708 position_information |= (((uint64_t)IVAL(pdata,4)) << 32);
5709 #else /* LARGE_SMB_OFF_T */
5710 if (IVAL(pdata,4) != 0) {
5711 /* more than 32 bits? */
5712 return NT_STATUS_INVALID_PARAMETER;
5714 #endif /* LARGE_SMB_OFF_T */
5716 DEBUG(10,("smb_file_position_information: Set file position "
5717 "information for file %s to %.0f\n", fsp_str_dbg(fsp),
5718 (double)position_information));
5719 fsp->fh->position_information = position_information;
5720 return NT_STATUS_OK;
5723 /****************************************************************************
5724 Deal with SMB_FILE_MODE_INFORMATION.
5725 ****************************************************************************/
5727 static NTSTATUS smb_file_mode_information(connection_struct *conn,
5728 const char *pdata,
5729 int total_data)
5731 uint32 mode;
5733 if (total_data < 4) {
5734 return NT_STATUS_INVALID_PARAMETER;
5736 mode = IVAL(pdata,0);
5737 if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
5738 return NT_STATUS_INVALID_PARAMETER;
5740 return NT_STATUS_OK;
5743 /****************************************************************************
5744 Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
5745 ****************************************************************************/
5747 static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
5748 struct smb_request *req,
5749 const char *pdata,
5750 int total_data,
5751 const struct smb_filename *smb_fname)
5753 char *link_target = NULL;
5754 const char *newname = smb_fname->base_name;
5755 NTSTATUS status = NT_STATUS_OK;
5756 TALLOC_CTX *ctx = talloc_tos();
5758 /* Set a symbolic link. */
5759 /* Don't allow this if follow links is false. */
5761 if (total_data == 0) {
5762 return NT_STATUS_INVALID_PARAMETER;
5765 if (!lp_symlinks(SNUM(conn))) {
5766 return NT_STATUS_ACCESS_DENIED;
5769 srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
5770 total_data, STR_TERMINATE);
5772 if (!link_target) {
5773 return NT_STATUS_INVALID_PARAMETER;
5776 /* !widelinks forces the target path to be within the share. */
5777 /* This means we can interpret the target as a pathname. */
5778 if (!lp_widelinks(SNUM(conn))) {
5779 char *rel_name = NULL;
5780 char *last_dirp = NULL;
5782 if (*link_target == '/') {
5783 /* No absolute paths allowed. */
5784 return NT_STATUS_ACCESS_DENIED;
5786 rel_name = talloc_strdup(ctx,newname);
5787 if (!rel_name) {
5788 return NT_STATUS_NO_MEMORY;
5790 last_dirp = strrchr_m(rel_name, '/');
5791 if (last_dirp) {
5792 last_dirp[1] = '\0';
5793 } else {
5794 rel_name = talloc_strdup(ctx,"./");
5795 if (!rel_name) {
5796 return NT_STATUS_NO_MEMORY;
5799 rel_name = talloc_asprintf_append(rel_name,
5800 "%s",
5801 link_target);
5802 if (!rel_name) {
5803 return NT_STATUS_NO_MEMORY;
5806 status = check_name(conn, rel_name);
5807 if (!NT_STATUS_IS_OK(status)) {
5808 return status;
5812 DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
5813 newname, link_target ));
5815 if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0) {
5816 return map_nt_error_from_unix(errno);
5819 return NT_STATUS_OK;
5822 /****************************************************************************
5823 Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
5824 ****************************************************************************/
5826 static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
5827 struct smb_request *req,
5828 const char *pdata, int total_data,
5829 const struct smb_filename *smb_fname_new)
5831 char *oldname = NULL;
5832 struct smb_filename *smb_fname_old = NULL;
5833 TALLOC_CTX *ctx = talloc_tos();
5834 NTSTATUS status = NT_STATUS_OK;
5836 /* Set a hard link. */
5837 if (total_data == 0) {
5838 return NT_STATUS_INVALID_PARAMETER;
5841 srvstr_get_path(ctx, pdata, req->flags2, &oldname, pdata,
5842 total_data, STR_TERMINATE, &status);
5843 if (!NT_STATUS_IS_OK(status)) {
5844 return status;
5847 DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
5848 smb_fname_str_dbg(smb_fname_new), oldname));
5850 status = filename_convert(ctx,
5851 conn,
5852 req->flags2 & FLAGS2_DFS_PATHNAMES,
5853 oldname,
5855 NULL,
5856 &smb_fname_old);
5857 if (!NT_STATUS_IS_OK(status)) {
5858 return status;
5861 return hardlink_internals(ctx, conn, smb_fname_old, smb_fname_new);
5864 /****************************************************************************
5865 Deal with SMB_FILE_RENAME_INFORMATION.
5866 ****************************************************************************/
5868 static NTSTATUS smb_file_rename_information(connection_struct *conn,
5869 struct smb_request *req,
5870 const char *pdata,
5871 int total_data,
5872 files_struct *fsp,
5873 struct smb_filename *smb_fname_src)
5875 bool overwrite;
5876 uint32 root_fid;
5877 uint32 len;
5878 char *newname = NULL;
5879 struct smb_filename *smb_fname_dst = NULL;
5880 bool dest_has_wcard = False;
5881 NTSTATUS status = NT_STATUS_OK;
5882 char *p;
5883 TALLOC_CTX *ctx = talloc_tos();
5885 if (total_data < 13) {
5886 return NT_STATUS_INVALID_PARAMETER;
5889 overwrite = (CVAL(pdata,0) ? True : False);
5890 root_fid = IVAL(pdata,4);
5891 len = IVAL(pdata,8);
5893 if (len > (total_data - 12) || (len == 0) || (root_fid != 0)) {
5894 return NT_STATUS_INVALID_PARAMETER;
5897 srvstr_get_path_wcard(ctx, pdata, req->flags2, &newname, &pdata[12],
5898 len, 0, &status,
5899 &dest_has_wcard);
5900 if (!NT_STATUS_IS_OK(status)) {
5901 return status;
5904 DEBUG(10,("smb_file_rename_information: got name |%s|\n",
5905 newname));
5907 status = resolve_dfspath_wcard(ctx, conn,
5908 req->flags2 & FLAGS2_DFS_PATHNAMES,
5909 newname,
5910 &newname,
5911 &dest_has_wcard);
5912 if (!NT_STATUS_IS_OK(status)) {
5913 return status;
5916 /* Check the new name has no '/' characters. */
5917 if (strchr_m(newname, '/')) {
5918 return NT_STATUS_NOT_SUPPORTED;
5921 if (fsp && fsp->base_fsp) {
5922 /* newname must be a stream name. */
5923 if (newname[0] != ':') {
5924 return NT_STATUS_NOT_SUPPORTED;
5927 /* Create an smb_fname to call rename_internals_fsp() with. */
5928 status = create_synthetic_smb_fname(talloc_tos(),
5929 fsp->base_fsp->fsp_name->base_name, newname, NULL,
5930 &smb_fname_dst);
5931 if (!NT_STATUS_IS_OK(status)) {
5932 goto out;
5936 * Set the original last component, since
5937 * rename_internals_fsp() requires it.
5939 smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
5940 newname);
5941 if (smb_fname_dst->original_lcomp == NULL) {
5942 status = NT_STATUS_NO_MEMORY;
5943 goto out;
5946 } else {
5948 * Build up an smb_fname_dst based on the filename passed in.
5949 * We basically just strip off the last component, and put on
5950 * the newname instead.
5952 char *base_name = NULL;
5954 /* newname must *not* be a stream name. */
5955 if (newname[0] == ':') {
5956 return NT_STATUS_NOT_SUPPORTED;
5960 * Strip off the last component (filename) of the path passed
5961 * in.
5963 base_name = talloc_strdup(ctx, smb_fname_src->base_name);
5964 if (!base_name) {
5965 return NT_STATUS_NO_MEMORY;
5967 p = strrchr_m(base_name, '/');
5968 if (p) {
5969 p[1] = '\0';
5970 } else {
5971 base_name = talloc_strdup(ctx, "./");
5972 if (!base_name) {
5973 return NT_STATUS_NO_MEMORY;
5976 /* Append the new name. */
5977 base_name = talloc_asprintf_append(base_name,
5978 "%s",
5979 newname);
5980 if (!base_name) {
5981 return NT_STATUS_NO_MEMORY;
5984 status = unix_convert(ctx, conn, base_name, &smb_fname_dst,
5985 (UCF_SAVE_LCOMP |
5986 (dest_has_wcard ?
5987 UCF_ALWAYS_ALLOW_WCARD_LCOMP :
5988 0)));
5990 /* If an error we expect this to be
5991 * NT_STATUS_OBJECT_PATH_NOT_FOUND */
5993 if (!NT_STATUS_IS_OK(status)) {
5994 if(!NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
5995 status)) {
5996 goto out;
5998 /* Create an smb_fname to call rename_internals_fsp() */
5999 status = create_synthetic_smb_fname(ctx,
6000 base_name, NULL,
6001 NULL,
6002 &smb_fname_dst);
6003 if (!NT_STATUS_IS_OK(status)) {
6004 goto out;
6009 if (fsp) {
6010 DEBUG(10,("smb_file_rename_information: "
6011 "SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
6012 fsp->fnum, fsp_str_dbg(fsp),
6013 smb_fname_str_dbg(smb_fname_dst)));
6014 status = rename_internals_fsp(conn, fsp, smb_fname_dst, 0,
6015 overwrite);
6016 } else {
6017 DEBUG(10,("smb_file_rename_information: "
6018 "SMB_FILE_RENAME_INFORMATION %s -> %s\n",
6019 smb_fname_str_dbg(smb_fname_src),
6020 smb_fname_str_dbg(smb_fname_dst)));
6021 status = rename_internals(ctx, conn, req, smb_fname_src,
6022 smb_fname_dst, 0, overwrite, false,
6023 dest_has_wcard,
6024 FILE_WRITE_ATTRIBUTES);
6026 out:
6027 TALLOC_FREE(smb_fname_dst);
6028 return status;
6031 /****************************************************************************
6032 Deal with SMB_SET_POSIX_ACL.
6033 ****************************************************************************/
6035 #if defined(HAVE_POSIX_ACLS)
6036 static NTSTATUS smb_set_posix_acl(connection_struct *conn,
6037 const char *pdata,
6038 int total_data,
6039 files_struct *fsp,
6040 const struct smb_filename *smb_fname)
6042 uint16 posix_acl_version;
6043 uint16 num_file_acls;
6044 uint16 num_def_acls;
6045 bool valid_file_acls = True;
6046 bool valid_def_acls = True;
6048 if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
6049 return NT_STATUS_INVALID_PARAMETER;
6051 posix_acl_version = SVAL(pdata,0);
6052 num_file_acls = SVAL(pdata,2);
6053 num_def_acls = SVAL(pdata,4);
6055 if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
6056 valid_file_acls = False;
6057 num_file_acls = 0;
6060 if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
6061 valid_def_acls = False;
6062 num_def_acls = 0;
6065 if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
6066 return NT_STATUS_INVALID_PARAMETER;
6069 if (total_data < SMB_POSIX_ACL_HEADER_SIZE +
6070 (num_file_acls+num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE) {
6071 return NT_STATUS_INVALID_PARAMETER;
6074 DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
6075 smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
6076 (unsigned int)num_file_acls,
6077 (unsigned int)num_def_acls));
6079 if (valid_file_acls && !set_unix_posix_acl(conn, fsp,
6080 smb_fname->base_name, num_file_acls,
6081 pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
6082 return map_nt_error_from_unix(errno);
6085 if (valid_def_acls && !set_unix_posix_default_acl(conn,
6086 smb_fname->base_name, &smb_fname->st, num_def_acls,
6087 pdata + SMB_POSIX_ACL_HEADER_SIZE +
6088 (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) {
6089 return map_nt_error_from_unix(errno);
6091 return NT_STATUS_OK;
6093 #endif
6095 /****************************************************************************
6096 Deal with SMB_SET_POSIX_LOCK.
6097 ****************************************************************************/
6099 static NTSTATUS smb_set_posix_lock(connection_struct *conn,
6100 struct smb_request *req,
6101 const char *pdata,
6102 int total_data,
6103 files_struct *fsp)
6105 uint64_t count;
6106 uint64_t offset;
6107 uint32 lock_pid;
6108 bool blocking_lock = False;
6109 enum brl_type lock_type;
6111 NTSTATUS status = NT_STATUS_OK;
6113 if (fsp == NULL || fsp->fh->fd == -1) {
6114 return NT_STATUS_INVALID_HANDLE;
6117 if (total_data != POSIX_LOCK_DATA_SIZE) {
6118 return NT_STATUS_INVALID_PARAMETER;
6121 switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
6122 case POSIX_LOCK_TYPE_READ:
6123 lock_type = READ_LOCK;
6124 break;
6125 case POSIX_LOCK_TYPE_WRITE:
6126 /* Return the right POSIX-mappable error code for files opened read-only. */
6127 if (!fsp->can_write) {
6128 return NT_STATUS_INVALID_HANDLE;
6130 lock_type = WRITE_LOCK;
6131 break;
6132 case POSIX_LOCK_TYPE_UNLOCK:
6133 lock_type = UNLOCK_LOCK;
6134 break;
6135 default:
6136 return NT_STATUS_INVALID_PARAMETER;
6139 if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
6140 blocking_lock = False;
6141 } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
6142 blocking_lock = True;
6143 } else {
6144 return NT_STATUS_INVALID_PARAMETER;
6147 if (!lp_blocking_locks(SNUM(conn))) {
6148 blocking_lock = False;
6151 lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
6152 #if defined(HAVE_LONGLONG)
6153 offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
6154 ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
6155 count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
6156 ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
6157 #else /* HAVE_LONGLONG */
6158 offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET);
6159 count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
6160 #endif /* HAVE_LONGLONG */
6162 DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u,"
6163 "lock_pid = %u, count = %.0f, offset = %.0f\n",
6164 fsp_str_dbg(fsp),
6165 (unsigned int)lock_type,
6166 (unsigned int)lock_pid,
6167 (double)count,
6168 (double)offset ));
6170 if (lock_type == UNLOCK_LOCK) {
6171 status = do_unlock(smbd_messaging_context(),
6172 fsp,
6173 lock_pid,
6174 count,
6175 offset,
6176 POSIX_LOCK);
6177 } else {
6178 uint32 block_smbpid;
6180 struct byte_range_lock *br_lck = do_lock(smbd_messaging_context(),
6181 fsp,
6182 lock_pid,
6183 count,
6184 offset,
6185 lock_type,
6186 POSIX_LOCK,
6187 blocking_lock,
6188 &status,
6189 &block_smbpid,
6190 NULL);
6192 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
6194 * A blocking lock was requested. Package up
6195 * this smb into a queued request and push it
6196 * onto the blocking lock queue.
6198 if(push_blocking_lock_request(br_lck,
6199 req,
6200 fsp,
6201 -1, /* infinite timeout. */
6203 lock_pid,
6204 lock_type,
6205 POSIX_LOCK,
6206 offset,
6207 count,
6208 block_smbpid)) {
6209 TALLOC_FREE(br_lck);
6210 return status;
6213 TALLOC_FREE(br_lck);
6216 return status;
6219 /****************************************************************************
6220 Deal with SMB_SET_FILE_BASIC_INFO.
6221 ****************************************************************************/
6223 static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
6224 const char *pdata,
6225 int total_data,
6226 files_struct *fsp,
6227 const struct smb_filename *smb_fname)
6229 /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
6230 struct smb_file_time ft;
6231 uint32 dosmode = 0;
6232 NTSTATUS status = NT_STATUS_OK;
6234 ZERO_STRUCT(ft);
6236 if (total_data < 36) {
6237 return NT_STATUS_INVALID_PARAMETER;
6240 /* Set the attributes */
6241 dosmode = IVAL(pdata,32);
6242 status = smb_set_file_dosmode(conn, smb_fname, dosmode);
6243 if (!NT_STATUS_IS_OK(status)) {
6244 return status;
6247 /* create time */
6248 ft.create_time = interpret_long_date(pdata);
6250 /* access time */
6251 ft.atime = interpret_long_date(pdata+8);
6253 /* write time. */
6254 ft.mtime = interpret_long_date(pdata+16);
6256 /* change time. */
6257 ft.ctime = interpret_long_date(pdata+24);
6259 DEBUG(10, ("smb_set_file_basic_info: file %s\n",
6260 smb_fname_str_dbg(smb_fname)));
6262 return smb_set_file_time(conn, fsp, smb_fname, &ft,
6263 true);
6266 /****************************************************************************
6267 Deal with SMB_INFO_STANDARD.
6268 ****************************************************************************/
6270 static NTSTATUS smb_set_info_standard(connection_struct *conn,
6271 const char *pdata,
6272 int total_data,
6273 files_struct *fsp,
6274 const struct smb_filename *smb_fname)
6276 struct smb_file_time ft;
6278 ZERO_STRUCT(ft);
6280 if (total_data < 12) {
6281 return NT_STATUS_INVALID_PARAMETER;
6284 /* create time */
6285 ft.create_time = convert_time_t_to_timespec(srv_make_unix_date2(pdata));
6286 /* access time */
6287 ft.atime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+4));
6288 /* write time */
6289 ft.mtime = convert_time_t_to_timespec(srv_make_unix_date2(pdata+8));
6291 DEBUG(10,("smb_set_info_standard: file %s\n",
6292 smb_fname_str_dbg(smb_fname)));
6294 return smb_set_file_time(conn,
6295 fsp,
6296 smb_fname,
6297 &ft,
6298 true);
6301 /****************************************************************************
6302 Deal with SMB_SET_FILE_ALLOCATION_INFO.
6303 ****************************************************************************/
6305 static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
6306 struct smb_request *req,
6307 const char *pdata,
6308 int total_data,
6309 files_struct *fsp,
6310 struct smb_filename *smb_fname)
6312 uint64_t allocation_size = 0;
6313 NTSTATUS status = NT_STATUS_OK;
6314 files_struct *new_fsp = NULL;
6316 if (!VALID_STAT(smb_fname->st)) {
6317 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6320 if (total_data < 8) {
6321 return NT_STATUS_INVALID_PARAMETER;
6324 allocation_size = (uint64_t)IVAL(pdata,0);
6325 #ifdef LARGE_SMB_OFF_T
6326 allocation_size |= (((uint64_t)IVAL(pdata,4)) << 32);
6327 #else /* LARGE_SMB_OFF_T */
6328 if (IVAL(pdata,4) != 0) {
6329 /* more than 32 bits? */
6330 return NT_STATUS_INVALID_PARAMETER;
6332 #endif /* LARGE_SMB_OFF_T */
6334 DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for "
6335 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
6336 (double)allocation_size));
6338 if (allocation_size) {
6339 allocation_size = smb_roundup(conn, allocation_size);
6342 DEBUG(10,("smb_set_file_allocation_info: file %s : setting new "
6343 "allocation size to %.0f\n", smb_fname_str_dbg(smb_fname),
6344 (double)allocation_size));
6346 if (fsp && fsp->fh->fd != -1) {
6347 /* Open file handle. */
6348 /* Only change if needed. */
6349 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
6350 if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
6351 return map_nt_error_from_unix(errno);
6354 /* But always update the time. */
6356 * This is equivalent to a write. Ensure it's seen immediately
6357 * if there are no pending writes.
6359 trigger_write_time_update_immediate(fsp);
6360 return NT_STATUS_OK;
6363 /* Pathname or stat or directory file. */
6364 status = SMB_VFS_CREATE_FILE(
6365 conn, /* conn */
6366 req, /* req */
6367 0, /* root_dir_fid */
6368 smb_fname, /* fname */
6369 FILE_WRITE_DATA, /* access_mask */
6370 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6371 FILE_SHARE_DELETE),
6372 FILE_OPEN, /* create_disposition*/
6373 0, /* create_options */
6374 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
6375 FORCE_OPLOCK_BREAK_TO_NONE, /* oplock_request */
6376 0, /* allocation_size */
6377 NULL, /* sd */
6378 NULL, /* ea_list */
6379 &new_fsp, /* result */
6380 NULL); /* pinfo */
6382 if (!NT_STATUS_IS_OK(status)) {
6383 /* NB. We check for open_was_deferred in the caller. */
6384 return status;
6387 /* Only change if needed. */
6388 if (allocation_size != get_file_size_stat(&smb_fname->st)) {
6389 if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) {
6390 status = map_nt_error_from_unix(errno);
6391 close_file(req, new_fsp, NORMAL_CLOSE);
6392 return status;
6396 /* Changing the allocation size should set the last mod time. */
6398 * This is equivalent to a write. Ensure it's seen immediately
6399 * if there are no pending writes.
6401 trigger_write_time_update_immediate(new_fsp);
6403 close_file(req, new_fsp, NORMAL_CLOSE);
6404 return NT_STATUS_OK;
6407 /****************************************************************************
6408 Deal with SMB_SET_FILE_END_OF_FILE_INFO.
6409 ****************************************************************************/
6411 static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
6412 struct smb_request *req,
6413 const char *pdata,
6414 int total_data,
6415 files_struct *fsp,
6416 const struct smb_filename *smb_fname)
6418 SMB_OFF_T size;
6420 if (total_data < 8) {
6421 return NT_STATUS_INVALID_PARAMETER;
6424 size = IVAL(pdata,0);
6425 #ifdef LARGE_SMB_OFF_T
6426 size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
6427 #else /* LARGE_SMB_OFF_T */
6428 if (IVAL(pdata,4) != 0) {
6429 /* more than 32 bits? */
6430 return NT_STATUS_INVALID_PARAMETER;
6432 #endif /* LARGE_SMB_OFF_T */
6433 DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for "
6434 "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
6435 (double)size));
6437 return smb_set_file_size(conn, req,
6438 fsp,
6439 smb_fname,
6440 &smb_fname->st,
6441 size);
6444 /****************************************************************************
6445 Allow a UNIX info mknod.
6446 ****************************************************************************/
6448 static NTSTATUS smb_unix_mknod(connection_struct *conn,
6449 const char *pdata,
6450 int total_data,
6451 const struct smb_filename *smb_fname)
6453 uint32 file_type = IVAL(pdata,56);
6454 #if defined(HAVE_MAKEDEV)
6455 uint32 dev_major = IVAL(pdata,60);
6456 uint32 dev_minor = IVAL(pdata,68);
6457 #endif
6458 SMB_DEV_T dev = (SMB_DEV_T)0;
6459 uint32 raw_unixmode = IVAL(pdata,84);
6460 NTSTATUS status;
6461 mode_t unixmode;
6463 if (total_data < 100) {
6464 return NT_STATUS_INVALID_PARAMETER;
6467 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6468 PERM_NEW_FILE, &unixmode);
6469 if (!NT_STATUS_IS_OK(status)) {
6470 return status;
6473 #if defined(HAVE_MAKEDEV)
6474 dev = makedev(dev_major, dev_minor);
6475 #endif
6477 switch (file_type) {
6478 #if defined(S_IFIFO)
6479 case UNIX_TYPE_FIFO:
6480 unixmode |= S_IFIFO;
6481 break;
6482 #endif
6483 #if defined(S_IFSOCK)
6484 case UNIX_TYPE_SOCKET:
6485 unixmode |= S_IFSOCK;
6486 break;
6487 #endif
6488 #if defined(S_IFCHR)
6489 case UNIX_TYPE_CHARDEV:
6490 unixmode |= S_IFCHR;
6491 break;
6492 #endif
6493 #if defined(S_IFBLK)
6494 case UNIX_TYPE_BLKDEV:
6495 unixmode |= S_IFBLK;
6496 break;
6497 #endif
6498 default:
6499 return NT_STATUS_INVALID_PARAMETER;
6502 DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
6503 "%.0f mode 0%o for file %s\n", (double)dev,
6504 (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
6506 /* Ok - do the mknod. */
6507 if (SMB_VFS_MKNOD(conn, smb_fname->base_name, unixmode, dev) != 0) {
6508 return map_nt_error_from_unix(errno);
6511 /* If any of the other "set" calls fail we
6512 * don't want to end up with a half-constructed mknod.
6515 if (lp_inherit_perms(SNUM(conn))) {
6516 char *parent;
6517 if (!parent_dirname(talloc_tos(), smb_fname->base_name,
6518 &parent, NULL)) {
6519 return NT_STATUS_NO_MEMORY;
6521 inherit_access_posix_acl(conn, parent, smb_fname->base_name,
6522 unixmode);
6523 TALLOC_FREE(parent);
6526 return NT_STATUS_OK;
6529 /****************************************************************************
6530 Deal with SMB_SET_FILE_UNIX_BASIC.
6531 ****************************************************************************/
6533 static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
6534 struct smb_request *req,
6535 const char *pdata,
6536 int total_data,
6537 files_struct *fsp,
6538 const struct smb_filename *smb_fname)
6540 struct smb_file_time ft;
6541 uint32 raw_unixmode;
6542 mode_t unixmode;
6543 SMB_OFF_T size = 0;
6544 uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
6545 gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
6546 NTSTATUS status = NT_STATUS_OK;
6547 bool delete_on_fail = False;
6548 enum perm_type ptype;
6549 files_struct *all_fsps = NULL;
6550 bool modify_mtime = true;
6551 struct file_id id;
6552 SMB_STRUCT_STAT sbuf;
6554 ZERO_STRUCT(ft);
6556 if (total_data < 100) {
6557 return NT_STATUS_INVALID_PARAMETER;
6560 if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
6561 IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
6562 size=IVAL(pdata,0); /* first 8 Bytes are size */
6563 #ifdef LARGE_SMB_OFF_T
6564 size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
6565 #else /* LARGE_SMB_OFF_T */
6566 if (IVAL(pdata,4) != 0) {
6567 /* more than 32 bits? */
6568 return NT_STATUS_INVALID_PARAMETER;
6570 #endif /* LARGE_SMB_OFF_T */
6573 ft.atime = interpret_long_date(pdata+24); /* access_time */
6574 ft.mtime = interpret_long_date(pdata+32); /* modification_time */
6575 set_owner = (uid_t)IVAL(pdata,40);
6576 set_grp = (gid_t)IVAL(pdata,48);
6577 raw_unixmode = IVAL(pdata,84);
6579 if (VALID_STAT(smb_fname->st)) {
6580 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
6581 ptype = PERM_EXISTING_DIR;
6582 } else {
6583 ptype = PERM_EXISTING_FILE;
6585 } else {
6586 ptype = PERM_NEW_FILE;
6589 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6590 ptype, &unixmode);
6591 if (!NT_STATUS_IS_OK(status)) {
6592 return status;
6595 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
6596 "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
6597 smb_fname_str_dbg(smb_fname), (double)size,
6598 (unsigned int)set_owner, (unsigned int)set_grp,
6599 (int)raw_unixmode));
6601 sbuf = smb_fname->st;
6603 if (!VALID_STAT(sbuf)) {
6604 struct smb_filename *smb_fname_tmp = NULL;
6606 * The only valid use of this is to create character and block
6607 * devices, and named pipes. This is deprecated (IMHO) and
6608 * a new info level should be used for mknod. JRA.
6611 status = smb_unix_mknod(conn,
6612 pdata,
6613 total_data,
6614 smb_fname);
6615 if (!NT_STATUS_IS_OK(status)) {
6616 return status;
6619 status = copy_smb_filename(talloc_tos(), smb_fname,
6620 &smb_fname_tmp);
6621 if (!NT_STATUS_IS_OK(status)) {
6622 return status;
6625 if (SMB_VFS_STAT(conn, smb_fname_tmp) != 0) {
6626 status = map_nt_error_from_unix(errno);
6627 TALLOC_FREE(smb_fname_tmp);
6628 SMB_VFS_UNLINK(conn, smb_fname);
6629 return status;
6632 sbuf = smb_fname_tmp->st;
6633 TALLOC_FREE(smb_fname_tmp);
6635 /* Ensure we don't try and change anything else. */
6636 raw_unixmode = SMB_MODE_NO_CHANGE;
6637 size = get_file_size_stat(&sbuf);
6638 ft.atime = sbuf.st_ex_atime;
6639 ft.mtime = sbuf.st_ex_mtime;
6641 * We continue here as we might want to change the
6642 * owner uid/gid.
6644 delete_on_fail = True;
6647 #if 1
6648 /* Horrible backwards compatibility hack as an old server bug
6649 * allowed a CIFS client bug to remain unnoticed :-(. JRA.
6650 * */
6652 if (!size) {
6653 size = get_file_size_stat(&sbuf);
6655 #endif
6658 * Deal with the UNIX specific mode set.
6661 if (raw_unixmode != SMB_MODE_NO_CHANGE) {
6662 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6663 "setting mode 0%o for file %s\n",
6664 (unsigned int)unixmode,
6665 smb_fname_str_dbg(smb_fname)));
6666 if (SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode) != 0) {
6667 return map_nt_error_from_unix(errno);
6672 * Deal with the UNIX specific uid set.
6675 if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
6676 (sbuf.st_ex_uid != set_owner)) {
6677 int ret;
6679 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6680 "changing owner %u for path %s\n",
6681 (unsigned int)set_owner,
6682 smb_fname_str_dbg(smb_fname)));
6684 if (S_ISLNK(sbuf.st_ex_mode)) {
6685 ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name,
6686 set_owner, (gid_t)-1);
6687 } else {
6688 ret = SMB_VFS_CHOWN(conn, smb_fname->base_name,
6689 set_owner, (gid_t)-1);
6692 if (ret != 0) {
6693 status = map_nt_error_from_unix(errno);
6694 if (delete_on_fail) {
6695 SMB_VFS_UNLINK(conn, smb_fname);
6697 return status;
6702 * Deal with the UNIX specific gid set.
6705 if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
6706 (sbuf.st_ex_gid != set_grp)) {
6707 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6708 "changing group %u for file %s\n",
6709 (unsigned int)set_owner,
6710 smb_fname_str_dbg(smb_fname)));
6711 if (SMB_VFS_CHOWN(conn, smb_fname->base_name, (uid_t)-1,
6712 set_grp) != 0) {
6713 status = map_nt_error_from_unix(errno);
6714 if (delete_on_fail) {
6715 SMB_VFS_UNLINK(conn, smb_fname);
6717 return status;
6721 /* Deal with any size changes. */
6723 status = smb_set_file_size(conn, req,
6724 fsp,
6725 smb_fname,
6726 &sbuf,
6727 size);
6728 if (!NT_STATUS_IS_OK(status)) {
6729 return status;
6732 /* Deal with any time changes. */
6733 if (null_timespec(ft.mtime) && null_timespec(ft.atime)) {
6734 /* No change, don't cancel anything. */
6735 return status;
6738 id = vfs_file_id_from_sbuf(conn, &sbuf);
6739 for(all_fsps = file_find_di_first(id); all_fsps;
6740 all_fsps = file_find_di_next(all_fsps)) {
6742 * We're setting the time explicitly for UNIX.
6743 * Cancel any pending changes over all handles.
6745 all_fsps->update_write_time_on_close = false;
6746 TALLOC_FREE(all_fsps->update_write_time_event);
6750 * Override the "setting_write_time"
6751 * parameter here as it almost does what
6752 * we need. Just remember if we modified
6753 * mtime and send the notify ourselves.
6755 if (null_timespec(ft.mtime)) {
6756 modify_mtime = false;
6759 status = smb_set_file_time(conn,
6760 fsp,
6761 smb_fname,
6762 &ft,
6763 false);
6764 if (modify_mtime) {
6765 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6766 FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
6768 return status;
6771 /****************************************************************************
6772 Deal with SMB_SET_FILE_UNIX_INFO2.
6773 ****************************************************************************/
6775 static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
6776 struct smb_request *req,
6777 const char *pdata,
6778 int total_data,
6779 files_struct *fsp,
6780 const struct smb_filename *smb_fname)
6782 NTSTATUS status;
6783 uint32 smb_fflags;
6784 uint32 smb_fmask;
6786 if (total_data < 116) {
6787 return NT_STATUS_INVALID_PARAMETER;
6790 /* Start by setting all the fields that are common between UNIX_BASIC
6791 * and UNIX_INFO2.
6793 status = smb_set_file_unix_basic(conn, req, pdata, total_data,
6794 fsp, smb_fname);
6795 if (!NT_STATUS_IS_OK(status)) {
6796 return status;
6799 smb_fflags = IVAL(pdata, 108);
6800 smb_fmask = IVAL(pdata, 112);
6802 /* NB: We should only attempt to alter the file flags if the client
6803 * sends a non-zero mask.
6805 if (smb_fmask != 0) {
6806 int stat_fflags = 0;
6808 if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
6809 smb_fmask, &stat_fflags)) {
6810 /* Client asked to alter a flag we don't understand. */
6811 return NT_STATUS_INVALID_PARAMETER;
6814 if (fsp && fsp->fh->fd != -1) {
6815 /* XXX: we should be using SMB_VFS_FCHFLAGS here. */
6816 return NT_STATUS_NOT_SUPPORTED;
6817 } else {
6818 if (SMB_VFS_CHFLAGS(conn, smb_fname->base_name,
6819 stat_fflags) != 0) {
6820 return map_nt_error_from_unix(errno);
6825 /* XXX: need to add support for changing the create_time here. You
6826 * can do this for paths on Darwin with setattrlist(2). The right way
6827 * to hook this up is probably by extending the VFS utimes interface.
6830 return NT_STATUS_OK;
6833 /****************************************************************************
6834 Create a directory with POSIX semantics.
6835 ****************************************************************************/
6837 static NTSTATUS smb_posix_mkdir(connection_struct *conn,
6838 struct smb_request *req,
6839 char **ppdata,
6840 int total_data,
6841 struct smb_filename *smb_fname,
6842 int *pdata_return_size)
6844 NTSTATUS status = NT_STATUS_OK;
6845 uint32 raw_unixmode = 0;
6846 uint32 mod_unixmode = 0;
6847 mode_t unixmode = (mode_t)0;
6848 files_struct *fsp = NULL;
6849 uint16 info_level_return = 0;
6850 int info;
6851 char *pdata = *ppdata;
6853 if (total_data < 18) {
6854 return NT_STATUS_INVALID_PARAMETER;
6857 raw_unixmode = IVAL(pdata,8);
6858 /* Next 4 bytes are not yet defined. */
6860 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6861 PERM_NEW_DIR, &unixmode);
6862 if (!NT_STATUS_IS_OK(status)) {
6863 return status;
6866 mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
6868 DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
6869 smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
6871 status = SMB_VFS_CREATE_FILE(
6872 conn, /* conn */
6873 req, /* req */
6874 0, /* root_dir_fid */
6875 smb_fname, /* fname */
6876 FILE_READ_ATTRIBUTES, /* access_mask */
6877 FILE_SHARE_NONE, /* share_access */
6878 FILE_CREATE, /* create_disposition*/
6879 FILE_DIRECTORY_FILE, /* create_options */
6880 mod_unixmode, /* file_attributes */
6881 0, /* oplock_request */
6882 0, /* allocation_size */
6883 NULL, /* sd */
6884 NULL, /* ea_list */
6885 &fsp, /* result */
6886 &info); /* pinfo */
6888 if (NT_STATUS_IS_OK(status)) {
6889 close_file(req, fsp, NORMAL_CLOSE);
6892 info_level_return = SVAL(pdata,16);
6894 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
6895 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
6896 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
6897 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
6898 } else {
6899 *pdata_return_size = 12;
6902 /* Realloc the data size */
6903 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
6904 if (*ppdata == NULL) {
6905 *pdata_return_size = 0;
6906 return NT_STATUS_NO_MEMORY;
6908 pdata = *ppdata;
6910 SSVAL(pdata,0,NO_OPLOCK_RETURN);
6911 SSVAL(pdata,2,0); /* No fnum. */
6912 SIVAL(pdata,4,info); /* Was directory created. */
6914 switch (info_level_return) {
6915 case SMB_QUERY_FILE_UNIX_BASIC:
6916 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
6917 SSVAL(pdata,10,0); /* Padding. */
6918 store_file_unix_basic(conn, pdata + 12, fsp,
6919 &smb_fname->st);
6920 break;
6921 case SMB_QUERY_FILE_UNIX_INFO2:
6922 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
6923 SSVAL(pdata,10,0); /* Padding. */
6924 store_file_unix_basic_info2(conn, pdata + 12, fsp,
6925 &smb_fname->st);
6926 break;
6927 default:
6928 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
6929 SSVAL(pdata,10,0); /* Padding. */
6930 break;
6933 return status;
6936 /****************************************************************************
6937 Open/Create a file with POSIX semantics.
6938 ****************************************************************************/
6940 static NTSTATUS smb_posix_open(connection_struct *conn,
6941 struct smb_request *req,
6942 char **ppdata,
6943 int total_data,
6944 struct smb_filename *smb_fname,
6945 int *pdata_return_size)
6947 bool extended_oplock_granted = False;
6948 char *pdata = *ppdata;
6949 uint32 flags = 0;
6950 uint32 wire_open_mode = 0;
6951 uint32 raw_unixmode = 0;
6952 uint32 mod_unixmode = 0;
6953 uint32 create_disp = 0;
6954 uint32 access_mask = 0;
6955 uint32 create_options = 0;
6956 NTSTATUS status = NT_STATUS_OK;
6957 mode_t unixmode = (mode_t)0;
6958 files_struct *fsp = NULL;
6959 int oplock_request = 0;
6960 int info = 0;
6961 uint16 info_level_return = 0;
6963 if (total_data < 18) {
6964 return NT_STATUS_INVALID_PARAMETER;
6967 flags = IVAL(pdata,0);
6968 oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
6969 if (oplock_request) {
6970 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
6973 wire_open_mode = IVAL(pdata,4);
6975 if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
6976 return smb_posix_mkdir(conn, req,
6977 ppdata,
6978 total_data,
6979 smb_fname,
6980 pdata_return_size);
6983 switch (wire_open_mode & SMB_ACCMODE) {
6984 case SMB_O_RDONLY:
6985 access_mask = FILE_READ_DATA;
6986 break;
6987 case SMB_O_WRONLY:
6988 access_mask = FILE_WRITE_DATA;
6989 break;
6990 case SMB_O_RDWR:
6991 access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
6992 break;
6993 default:
6994 DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
6995 (unsigned int)wire_open_mode ));
6996 return NT_STATUS_INVALID_PARAMETER;
6999 wire_open_mode &= ~SMB_ACCMODE;
7001 if((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) == (SMB_O_CREAT | SMB_O_EXCL)) {
7002 create_disp = FILE_CREATE;
7003 } else if((wire_open_mode & (SMB_O_CREAT | SMB_O_TRUNC)) == (SMB_O_CREAT | SMB_O_TRUNC)) {
7004 create_disp = FILE_OVERWRITE_IF;
7005 } else if((wire_open_mode & SMB_O_CREAT) == SMB_O_CREAT) {
7006 create_disp = FILE_OPEN_IF;
7007 } else if ((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL | SMB_O_TRUNC)) == 0) {
7008 create_disp = FILE_OPEN;
7009 } else {
7010 DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
7011 (unsigned int)wire_open_mode ));
7012 return NT_STATUS_INVALID_PARAMETER;
7015 raw_unixmode = IVAL(pdata,8);
7016 /* Next 4 bytes are not yet defined. */
7018 status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
7019 (VALID_STAT(smb_fname->st) ?
7020 PERM_EXISTING_FILE : PERM_NEW_FILE),
7021 &unixmode);
7023 if (!NT_STATUS_IS_OK(status)) {
7024 return status;
7027 mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
7029 if (wire_open_mode & SMB_O_SYNC) {
7030 create_options |= FILE_WRITE_THROUGH;
7032 if (wire_open_mode & SMB_O_APPEND) {
7033 access_mask |= FILE_APPEND_DATA;
7035 if (wire_open_mode & SMB_O_DIRECT) {
7036 mod_unixmode |= FILE_FLAG_NO_BUFFERING;
7039 DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
7040 smb_fname_str_dbg(smb_fname),
7041 (unsigned int)wire_open_mode,
7042 (unsigned int)unixmode ));
7044 status = SMB_VFS_CREATE_FILE(
7045 conn, /* conn */
7046 req, /* req */
7047 0, /* root_dir_fid */
7048 smb_fname, /* fname */
7049 access_mask, /* access_mask */
7050 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7051 FILE_SHARE_DELETE),
7052 create_disp, /* create_disposition*/
7053 FILE_NON_DIRECTORY_FILE, /* create_options */
7054 mod_unixmode, /* file_attributes */
7055 oplock_request, /* oplock_request */
7056 0, /* allocation_size */
7057 NULL, /* sd */
7058 NULL, /* ea_list */
7059 &fsp, /* result */
7060 &info); /* pinfo */
7062 if (!NT_STATUS_IS_OK(status)) {
7063 return status;
7066 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
7067 extended_oplock_granted = True;
7070 if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
7071 extended_oplock_granted = True;
7074 info_level_return = SVAL(pdata,16);
7076 /* Allocate the correct return size. */
7078 if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
7079 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
7080 } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
7081 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
7082 } else {
7083 *pdata_return_size = 12;
7086 /* Realloc the data size */
7087 *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
7088 if (*ppdata == NULL) {
7089 close_file(req, fsp, ERROR_CLOSE);
7090 *pdata_return_size = 0;
7091 return NT_STATUS_NO_MEMORY;
7093 pdata = *ppdata;
7095 if (extended_oplock_granted) {
7096 if (flags & REQUEST_BATCH_OPLOCK) {
7097 SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
7098 } else {
7099 SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
7101 } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
7102 SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
7103 } else {
7104 SSVAL(pdata,0,NO_OPLOCK_RETURN);
7107 SSVAL(pdata,2,fsp->fnum);
7108 SIVAL(pdata,4,info); /* Was file created etc. */
7110 switch (info_level_return) {
7111 case SMB_QUERY_FILE_UNIX_BASIC:
7112 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
7113 SSVAL(pdata,10,0); /* padding. */
7114 store_file_unix_basic(conn, pdata + 12, fsp,
7115 &smb_fname->st);
7116 break;
7117 case SMB_QUERY_FILE_UNIX_INFO2:
7118 SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
7119 SSVAL(pdata,10,0); /* padding. */
7120 store_file_unix_basic_info2(conn, pdata + 12, fsp,
7121 &smb_fname->st);
7122 break;
7123 default:
7124 SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
7125 SSVAL(pdata,10,0); /* padding. */
7126 break;
7128 return NT_STATUS_OK;
7131 /****************************************************************************
7132 Delete a file with POSIX semantics.
7133 ****************************************************************************/
7135 static NTSTATUS smb_posix_unlink(connection_struct *conn,
7136 struct smb_request *req,
7137 const char *pdata,
7138 int total_data,
7139 struct smb_filename *smb_fname)
7141 NTSTATUS status = NT_STATUS_OK;
7142 files_struct *fsp = NULL;
7143 uint16 flags = 0;
7144 char del = 1;
7145 int info = 0;
7146 int create_options = 0;
7147 int i;
7148 struct share_mode_lock *lck = NULL;
7150 if (total_data < 2) {
7151 return NT_STATUS_INVALID_PARAMETER;
7154 flags = SVAL(pdata,0);
7156 if (!VALID_STAT(smb_fname->st)) {
7157 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
7160 if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
7161 !VALID_STAT_OF_DIR(smb_fname->st)) {
7162 return NT_STATUS_NOT_A_DIRECTORY;
7165 DEBUG(10,("smb_posix_unlink: %s %s\n",
7166 (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
7167 smb_fname_str_dbg(smb_fname)));
7169 if (VALID_STAT_OF_DIR(smb_fname->st)) {
7170 create_options |= FILE_DIRECTORY_FILE;
7173 status = SMB_VFS_CREATE_FILE(
7174 conn, /* conn */
7175 req, /* req */
7176 0, /* root_dir_fid */
7177 smb_fname, /* fname */
7178 DELETE_ACCESS, /* access_mask */
7179 (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
7180 FILE_SHARE_DELETE),
7181 FILE_OPEN, /* create_disposition*/
7182 create_options, /* create_options */
7183 FILE_FLAG_POSIX_SEMANTICS|0777, /* file_attributes */
7184 0, /* oplock_request */
7185 0, /* allocation_size */
7186 NULL, /* sd */
7187 NULL, /* ea_list */
7188 &fsp, /* result */
7189 &info); /* pinfo */
7191 if (!NT_STATUS_IS_OK(status)) {
7192 return status;
7196 * Don't lie to client. If we can't really delete due to
7197 * non-POSIX opens return SHARING_VIOLATION.
7200 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
7201 NULL);
7202 if (lck == NULL) {
7203 DEBUG(0, ("smb_posix_unlink: Could not get share mode "
7204 "lock for file %s\n", fsp_str_dbg(fsp)));
7205 close_file(req, fsp, NORMAL_CLOSE);
7206 return NT_STATUS_INVALID_PARAMETER;
7210 * See if others still have the file open. If this is the case, then
7211 * don't delete. If all opens are POSIX delete we can set the delete
7212 * on close disposition.
7214 for (i=0; i<lck->num_share_modes; i++) {
7215 struct share_mode_entry *e = &lck->share_modes[i];
7216 if (is_valid_share_mode_entry(e)) {
7217 if (e->flags & SHARE_MODE_FLAG_POSIX_OPEN) {
7218 continue;
7220 /* Fail with sharing violation. */
7221 close_file(req, fsp, NORMAL_CLOSE);
7222 TALLOC_FREE(lck);
7223 return NT_STATUS_SHARING_VIOLATION;
7228 * Set the delete on close.
7230 status = smb_set_file_disposition_info(conn,
7231 &del,
7233 fsp,
7234 smb_fname);
7236 if (!NT_STATUS_IS_OK(status)) {
7237 close_file(req, fsp, NORMAL_CLOSE);
7238 TALLOC_FREE(lck);
7239 return status;
7241 TALLOC_FREE(lck);
7242 return close_file(req, fsp, NORMAL_CLOSE);
7245 NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
7246 struct smb_request *req,
7247 TALLOC_CTX *mem_ctx,
7248 uint16_t info_level,
7249 files_struct *fsp,
7250 struct smb_filename *smb_fname,
7251 char **ppdata, int total_data,
7252 int *ret_data_size)
7254 char *pdata = *ppdata;
7255 NTSTATUS status = NT_STATUS_OK;
7256 int data_return_size = 0;
7258 *ret_data_size = 0;
7260 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
7261 return NT_STATUS_INVALID_LEVEL;
7264 if (!CAN_WRITE(conn)) {
7265 /* Allow POSIX opens. The open path will deny
7266 * any non-readonly opens. */
7267 if (info_level != SMB_POSIX_PATH_OPEN) {
7268 return NT_STATUS_DOS(ERRSRV, ERRaccess);
7272 DEBUG(3,("smbd_do_setfilepathinfo: %s (fnum %d) info_level=%d "
7273 "totdata=%d\n", smb_fname_str_dbg(smb_fname),
7274 fsp ? fsp->fnum : -1, info_level, total_data));
7276 switch (info_level) {
7278 case SMB_INFO_STANDARD:
7280 status = smb_set_info_standard(conn,
7281 pdata,
7282 total_data,
7283 fsp,
7284 smb_fname);
7285 break;
7288 case SMB_INFO_SET_EA:
7290 status = smb_info_set_ea(conn,
7291 pdata,
7292 total_data,
7293 fsp,
7294 smb_fname);
7295 break;
7298 case SMB_SET_FILE_BASIC_INFO:
7299 case SMB_FILE_BASIC_INFORMATION:
7301 status = smb_set_file_basic_info(conn,
7302 pdata,
7303 total_data,
7304 fsp,
7305 smb_fname);
7306 break;
7309 case SMB_FILE_ALLOCATION_INFORMATION:
7310 case SMB_SET_FILE_ALLOCATION_INFO:
7312 status = smb_set_file_allocation_info(conn, req,
7313 pdata,
7314 total_data,
7315 fsp,
7316 smb_fname);
7317 break;
7320 case SMB_FILE_END_OF_FILE_INFORMATION:
7321 case SMB_SET_FILE_END_OF_FILE_INFO:
7323 status = smb_set_file_end_of_file_info(conn, req,
7324 pdata,
7325 total_data,
7326 fsp,
7327 smb_fname);
7328 break;
7331 case SMB_FILE_DISPOSITION_INFORMATION:
7332 case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
7334 #if 0
7335 /* JRA - We used to just ignore this on a path ?
7336 * Shouldn't this be invalid level on a pathname
7337 * based call ?
7339 if (tran_call != TRANSACT2_SETFILEINFO) {
7340 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
7342 #endif
7343 status = smb_set_file_disposition_info(conn,
7344 pdata,
7345 total_data,
7346 fsp,
7347 smb_fname);
7348 break;
7351 case SMB_FILE_POSITION_INFORMATION:
7353 status = smb_file_position_information(conn,
7354 pdata,
7355 total_data,
7356 fsp);
7357 break;
7360 /* From tridge Samba4 :
7361 * MODE_INFORMATION in setfileinfo (I have no
7362 * idea what "mode information" on a file is - it takes a value of 0,
7363 * 2, 4 or 6. What could it be?).
7366 case SMB_FILE_MODE_INFORMATION:
7368 status = smb_file_mode_information(conn,
7369 pdata,
7370 total_data);
7371 break;
7375 * CIFS UNIX extensions.
7378 case SMB_SET_FILE_UNIX_BASIC:
7380 status = smb_set_file_unix_basic(conn, req,
7381 pdata,
7382 total_data,
7383 fsp,
7384 smb_fname);
7385 break;
7388 case SMB_SET_FILE_UNIX_INFO2:
7390 status = smb_set_file_unix_info2(conn, req,
7391 pdata,
7392 total_data,
7393 fsp,
7394 smb_fname);
7395 break;
7398 case SMB_SET_FILE_UNIX_LINK:
7400 if (fsp) {
7401 /* We must have a pathname for this. */
7402 return NT_STATUS_INVALID_LEVEL;
7404 status = smb_set_file_unix_link(conn, req, pdata,
7405 total_data, smb_fname);
7406 break;
7409 case SMB_SET_FILE_UNIX_HLINK:
7411 if (fsp) {
7412 /* We must have a pathname for this. */
7413 return NT_STATUS_INVALID_LEVEL;
7415 status = smb_set_file_unix_hlink(conn, req,
7416 pdata, total_data,
7417 smb_fname);
7418 break;
7421 case SMB_FILE_RENAME_INFORMATION:
7423 status = smb_file_rename_information(conn, req,
7424 pdata, total_data,
7425 fsp, smb_fname);
7426 break;
7429 #if defined(HAVE_POSIX_ACLS)
7430 case SMB_SET_POSIX_ACL:
7432 status = smb_set_posix_acl(conn,
7433 pdata,
7434 total_data,
7435 fsp,
7436 smb_fname);
7437 break;
7439 #endif
7441 case SMB_SET_POSIX_LOCK:
7443 if (!fsp) {
7444 return NT_STATUS_INVALID_LEVEL;
7446 status = smb_set_posix_lock(conn, req,
7447 pdata, total_data, fsp);
7448 break;
7451 case SMB_POSIX_PATH_OPEN:
7453 if (fsp) {
7454 /* We must have a pathname for this. */
7455 return NT_STATUS_INVALID_LEVEL;
7458 status = smb_posix_open(conn, req,
7459 ppdata,
7460 total_data,
7461 smb_fname,
7462 &data_return_size);
7463 break;
7466 case SMB_POSIX_PATH_UNLINK:
7468 if (fsp) {
7469 /* We must have a pathname for this. */
7470 return NT_STATUS_INVALID_LEVEL;
7473 status = smb_posix_unlink(conn, req,
7474 pdata,
7475 total_data,
7476 smb_fname);
7477 break;
7480 default:
7481 return NT_STATUS_INVALID_LEVEL;
7484 if (!NT_STATUS_IS_OK(status)) {
7485 return status;
7488 *ret_data_size = data_return_size;
7489 return NT_STATUS_OK;
7492 /****************************************************************************
7493 Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname).
7494 ****************************************************************************/
7496 static void call_trans2setfilepathinfo(connection_struct *conn,
7497 struct smb_request *req,
7498 unsigned int tran_call,
7499 char **pparams, int total_params,
7500 char **ppdata, int total_data,
7501 unsigned int max_data_bytes)
7503 char *params = *pparams;
7504 char *pdata = *ppdata;
7505 uint16 info_level;
7506 struct smb_filename *smb_fname = NULL;
7507 files_struct *fsp = NULL;
7508 NTSTATUS status = NT_STATUS_OK;
7509 int data_return_size = 0;
7511 if (!params) {
7512 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7513 return;
7516 if (tran_call == TRANSACT2_SETFILEINFO) {
7517 if (total_params < 4) {
7518 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7519 return;
7522 fsp = file_fsp(req, SVAL(params,0));
7523 /* Basic check for non-null fsp. */
7524 if (!check_fsp_open(conn, req, fsp)) {
7525 return;
7527 info_level = SVAL(params,2);
7529 status = copy_smb_filename(talloc_tos(), fsp->fsp_name,
7530 &smb_fname);
7531 if (!NT_STATUS_IS_OK(status)) {
7532 reply_nterror(req, status);
7533 return;
7536 if(fsp->is_directory || fsp->fh->fd == -1) {
7538 * This is actually a SETFILEINFO on a directory
7539 * handle (returned from an NT SMB). NT5.0 seems
7540 * to do this call. JRA.
7542 if (INFO_LEVEL_IS_UNIX(info_level)) {
7543 /* Always do lstat for UNIX calls. */
7544 if (SMB_VFS_LSTAT(conn, smb_fname)) {
7545 DEBUG(3,("call_trans2setfilepathinfo: "
7546 "SMB_VFS_LSTAT of %s failed "
7547 "(%s)\n",
7548 smb_fname_str_dbg(smb_fname),
7549 strerror(errno)));
7550 reply_nterror(req, map_nt_error_from_unix(errno));
7551 return;
7553 } else {
7554 if (SMB_VFS_STAT(conn, smb_fname) != 0) {
7555 DEBUG(3,("call_trans2setfilepathinfo: "
7556 "fileinfo of %s failed (%s)\n",
7557 smb_fname_str_dbg(smb_fname),
7558 strerror(errno)));
7559 reply_nterror(req, map_nt_error_from_unix(errno));
7560 return;
7563 } else if (fsp->print_file) {
7565 * Doing a DELETE_ON_CLOSE should cancel a print job.
7567 if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
7568 fsp->fh->private_options |= FILE_DELETE_ON_CLOSE;
7570 DEBUG(3,("call_trans2setfilepathinfo: "
7571 "Cancelling print job (%s)\n",
7572 fsp_str_dbg(fsp)));
7574 SSVAL(params,0,0);
7575 send_trans2_replies(conn, req, params, 2,
7576 *ppdata, 0,
7577 max_data_bytes);
7578 return;
7579 } else {
7580 reply_doserror(req, ERRDOS, ERRbadpath);
7581 return;
7583 } else {
7585 * Original code - this is an open file.
7587 if (!check_fsp(conn, req, fsp)) {
7588 return;
7591 if (SMB_VFS_FSTAT(fsp, &smb_fname->st) != 0) {
7592 DEBUG(3,("call_trans2setfilepathinfo: fstat "
7593 "of fnum %d failed (%s)\n", fsp->fnum,
7594 strerror(errno)));
7595 reply_nterror(req, map_nt_error_from_unix(errno));
7596 return;
7599 } else {
7600 char *fname = NULL;
7602 /* set path info */
7603 if (total_params < 7) {
7604 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7605 return;
7608 info_level = SVAL(params,0);
7609 srvstr_get_path(req, params, req->flags2, &fname, &params[6],
7610 total_params - 6, STR_TERMINATE,
7611 &status);
7612 if (!NT_STATUS_IS_OK(status)) {
7613 reply_nterror(req, status);
7614 return;
7617 status = filename_convert(req, conn,
7618 req->flags2 & FLAGS2_DFS_PATHNAMES,
7619 fname,
7621 NULL,
7622 &smb_fname);
7623 if (!NT_STATUS_IS_OK(status)) {
7624 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7625 reply_botherror(req,
7626 NT_STATUS_PATH_NOT_COVERED,
7627 ERRSRV, ERRbadpath);
7628 return;
7630 reply_nterror(req, status);
7631 return;
7634 if (INFO_LEVEL_IS_UNIX(info_level)) {
7636 * For CIFS UNIX extensions the target name may not exist.
7639 /* Always do lstat for UNIX calls. */
7640 SMB_VFS_LSTAT(conn, smb_fname);
7642 } else if (!VALID_STAT(smb_fname->st) &&
7643 SMB_VFS_STAT(conn, smb_fname)) {
7644 DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of "
7645 "%s failed (%s)\n",
7646 smb_fname_str_dbg(smb_fname),
7647 strerror(errno)));
7648 reply_nterror(req, map_nt_error_from_unix(errno));
7649 return;
7653 DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d "
7654 "totdata=%d\n", tran_call, smb_fname_str_dbg(smb_fname),
7655 fsp ? fsp->fnum : -1, info_level,total_data));
7657 /* Realloc the parameter size */
7658 *pparams = (char *)SMB_REALLOC(*pparams,2);
7659 if (*pparams == NULL) {
7660 reply_nterror(req, NT_STATUS_NO_MEMORY);
7661 return;
7663 params = *pparams;
7665 SSVAL(params,0,0);
7667 status = smbd_do_setfilepathinfo(conn, req, req,
7668 info_level,
7669 fsp,
7670 smb_fname,
7671 ppdata, total_data,
7672 &data_return_size);
7673 if (!NT_STATUS_IS_OK(status)) {
7674 if (open_was_deferred(req->mid)) {
7675 /* We have re-scheduled this call. */
7676 return;
7678 if (blocking_lock_was_deferred(req->mid)) {
7679 /* We have re-scheduled this call. */
7680 return;
7682 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7683 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
7684 ERRSRV, ERRbadpath);
7685 return;
7687 if (info_level == SMB_POSIX_PATH_OPEN) {
7688 reply_openerror(req, status);
7689 return;
7692 reply_nterror(req, status);
7693 return;
7696 send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size,
7697 max_data_bytes);
7699 return;
7702 /****************************************************************************
7703 Reply to a TRANS2_MKDIR (make directory with extended attributes).
7704 ****************************************************************************/
7706 static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
7707 char **pparams, int total_params,
7708 char **ppdata, int total_data,
7709 unsigned int max_data_bytes)
7711 struct smb_filename *smb_dname = NULL;
7712 char *params = *pparams;
7713 char *pdata = *ppdata;
7714 char *directory = NULL;
7715 NTSTATUS status = NT_STATUS_OK;
7716 struct ea_list *ea_list = NULL;
7717 TALLOC_CTX *ctx = talloc_tos();
7719 if (!CAN_WRITE(conn)) {
7720 reply_doserror(req, ERRSRV, ERRaccess);
7721 return;
7724 if (total_params < 5) {
7725 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7726 return;
7729 srvstr_get_path(ctx, params, req->flags2, &directory, &params[4],
7730 total_params - 4, STR_TERMINATE,
7731 &status);
7732 if (!NT_STATUS_IS_OK(status)) {
7733 reply_nterror(req, status);
7734 return;
7737 DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
7739 status = filename_convert(ctx,
7740 conn,
7741 req->flags2 & FLAGS2_DFS_PATHNAMES,
7742 directory,
7744 NULL,
7745 &smb_dname);
7747 if (!NT_STATUS_IS_OK(status)) {
7748 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
7749 reply_botherror(req,
7750 NT_STATUS_PATH_NOT_COVERED,
7751 ERRSRV, ERRbadpath);
7752 return;
7754 reply_nterror(req, status);
7755 return;
7758 /* Any data in this call is an EA list. */
7759 if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
7760 reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
7761 goto out;
7765 * OS/2 workplace shell seems to send SET_EA requests of "null"
7766 * length (4 bytes containing IVAL 4).
7767 * They seem to have no effect. Bug #3212. JRA.
7770 if (total_data != 4) {
7771 if (total_data < 10) {
7772 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7773 goto out;
7776 if (IVAL(pdata,0) > total_data) {
7777 DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
7778 IVAL(pdata,0), (unsigned int)total_data));
7779 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7780 goto out;
7783 ea_list = read_ea_list(talloc_tos(), pdata + 4,
7784 total_data - 4);
7785 if (!ea_list) {
7786 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7787 goto out;
7790 /* If total_data == 4 Windows doesn't care what values
7791 * are placed in that field, it just ignores them.
7792 * The System i QNTC IBM SMB client puts bad values here,
7793 * so ignore them. */
7795 status = create_directory(conn, req, smb_dname);
7797 if (!NT_STATUS_IS_OK(status)) {
7798 reply_nterror(req, status);
7799 goto out;
7802 /* Try and set any given EA. */
7803 if (ea_list) {
7804 status = set_ea(conn, NULL, smb_dname, ea_list);
7805 if (!NT_STATUS_IS_OK(status)) {
7806 reply_nterror(req, status);
7807 goto out;
7811 /* Realloc the parameter and data sizes */
7812 *pparams = (char *)SMB_REALLOC(*pparams,2);
7813 if(*pparams == NULL) {
7814 reply_nterror(req, NT_STATUS_NO_MEMORY);
7815 goto out;
7817 params = *pparams;
7819 SSVAL(params,0,0);
7821 send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes);
7823 out:
7824 TALLOC_FREE(smb_dname);
7825 return;
7828 /****************************************************************************
7829 Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
7830 We don't actually do this - we just send a null response.
7831 ****************************************************************************/
7833 static void call_trans2findnotifyfirst(connection_struct *conn,
7834 struct smb_request *req,
7835 char **pparams, int total_params,
7836 char **ppdata, int total_data,
7837 unsigned int max_data_bytes)
7839 char *params = *pparams;
7840 uint16 info_level;
7842 if (total_params < 6) {
7843 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7844 return;
7847 info_level = SVAL(params,4);
7848 DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
7850 switch (info_level) {
7851 case 1:
7852 case 2:
7853 break;
7854 default:
7855 reply_nterror(req, NT_STATUS_INVALID_LEVEL);
7856 return;
7859 /* Realloc the parameter and data sizes */
7860 *pparams = (char *)SMB_REALLOC(*pparams,6);
7861 if (*pparams == NULL) {
7862 reply_nterror(req, NT_STATUS_NO_MEMORY);
7863 return;
7865 params = *pparams;
7867 SSVAL(params,0,fnf_handle);
7868 SSVAL(params,2,0); /* No changes */
7869 SSVAL(params,4,0); /* No EA errors */
7871 fnf_handle++;
7873 if(fnf_handle == 0)
7874 fnf_handle = 257;
7876 send_trans2_replies(conn, req, params, 6, *ppdata, 0, max_data_bytes);
7878 return;
7881 /****************************************************************************
7882 Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for
7883 changes). Currently this does nothing.
7884 ****************************************************************************/
7886 static void call_trans2findnotifynext(connection_struct *conn,
7887 struct smb_request *req,
7888 char **pparams, int total_params,
7889 char **ppdata, int total_data,
7890 unsigned int max_data_bytes)
7892 char *params = *pparams;
7894 DEBUG(3,("call_trans2findnotifynext\n"));
7896 /* Realloc the parameter and data sizes */
7897 *pparams = (char *)SMB_REALLOC(*pparams,4);
7898 if (*pparams == NULL) {
7899 reply_nterror(req, NT_STATUS_NO_MEMORY);
7900 return;
7902 params = *pparams;
7904 SSVAL(params,0,0); /* No changes */
7905 SSVAL(params,2,0); /* No EA errors */
7907 send_trans2_replies(conn, req, params, 4, *ppdata, 0, max_data_bytes);
7909 return;
7912 /****************************************************************************
7913 Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
7914 ****************************************************************************/
7916 static void call_trans2getdfsreferral(connection_struct *conn,
7917 struct smb_request *req,
7918 char **pparams, int total_params,
7919 char **ppdata, int total_data,
7920 unsigned int max_data_bytes)
7922 char *params = *pparams;
7923 char *pathname = NULL;
7924 int reply_size = 0;
7925 int max_referral_level;
7926 NTSTATUS status = NT_STATUS_OK;
7927 TALLOC_CTX *ctx = talloc_tos();
7929 DEBUG(10,("call_trans2getdfsreferral\n"));
7931 if (total_params < 3) {
7932 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7933 return;
7936 max_referral_level = SVAL(params,0);
7938 if(!lp_host_msdfs()) {
7939 reply_doserror(req, ERRDOS, ERRbadfunc);
7940 return;
7943 srvstr_pull_talloc(ctx, params, req->flags2, &pathname, &params[2],
7944 total_params - 2, STR_TERMINATE);
7945 if (!pathname) {
7946 reply_nterror(req, NT_STATUS_NOT_FOUND);
7947 return;
7949 if((reply_size = setup_dfs_referral(conn, pathname, max_referral_level,
7950 ppdata,&status)) < 0) {
7951 reply_nterror(req, status);
7952 return;
7955 SSVAL(req->inbuf, smb_flg2,
7956 SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
7957 send_trans2_replies(conn, req,0,0,*ppdata,reply_size, max_data_bytes);
7959 return;
7962 #define LMCAT_SPL 0x53
7963 #define LMFUNC_GETJOBID 0x60
7965 /****************************************************************************
7966 Reply to a TRANS2_IOCTL - used for OS/2 printing.
7967 ****************************************************************************/
7969 static void call_trans2ioctl(connection_struct *conn,
7970 struct smb_request *req,
7971 char **pparams, int total_params,
7972 char **ppdata, int total_data,
7973 unsigned int max_data_bytes)
7975 char *pdata = *ppdata;
7976 files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
7978 /* check for an invalid fid before proceeding */
7980 if (!fsp) {
7981 reply_doserror(req, ERRDOS, ERRbadfid);
7982 return;
7985 if ((SVAL(req->vwv+16, 0) == LMCAT_SPL)
7986 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
7987 *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
7988 if (*ppdata == NULL) {
7989 reply_nterror(req, NT_STATUS_NO_MEMORY);
7990 return;
7992 pdata = *ppdata;
7994 /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
7995 CAN ACCEPT THIS IN UNICODE. JRA. */
7997 SSVAL(pdata,0,fsp->rap_print_jobid); /* Job number */
7998 srvstr_push(pdata, req->flags2, pdata + 2,
7999 global_myname(), 15,
8000 STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */
8001 srvstr_push(pdata, req->flags2, pdata+18,
8002 lp_servicename(SNUM(conn)), 13,
8003 STR_ASCII|STR_TERMINATE); /* Service name */
8004 send_trans2_replies(conn, req, *pparams, 0, *ppdata, 32,
8005 max_data_bytes);
8006 return;
8009 DEBUG(2,("Unknown TRANS2_IOCTL\n"));
8010 reply_doserror(req, ERRSRV, ERRerror);
8013 /****************************************************************************
8014 Reply to a SMBfindclose (stop trans2 directory search).
8015 ****************************************************************************/
8017 void reply_findclose(struct smb_request *req)
8019 int dptr_num;
8020 struct smbd_server_connection *sconn = smbd_server_conn;
8022 START_PROFILE(SMBfindclose);
8024 if (req->wct < 1) {
8025 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8026 END_PROFILE(SMBfindclose);
8027 return;
8030 dptr_num = SVALS(req->vwv+0, 0);
8032 DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
8034 dptr_close(sconn, &dptr_num);
8036 reply_outbuf(req, 0, 0);
8038 DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));
8040 END_PROFILE(SMBfindclose);
8041 return;
8044 /****************************************************************************
8045 Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search).
8046 ****************************************************************************/
8048 void reply_findnclose(struct smb_request *req)
8050 int dptr_num;
8052 START_PROFILE(SMBfindnclose);
8054 if (req->wct < 1) {
8055 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8056 END_PROFILE(SMBfindnclose);
8057 return;
8060 dptr_num = SVAL(req->vwv+0, 0);
8062 DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num));
8064 /* We never give out valid handles for a
8065 findnotifyfirst - so any dptr_num is ok here.
8066 Just ignore it. */
8068 reply_outbuf(req, 0, 0);
8070 DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));
8072 END_PROFILE(SMBfindnclose);
8073 return;
8076 static void handle_trans2(connection_struct *conn, struct smb_request *req,
8077 struct trans_state *state)
8079 if (Protocol >= PROTOCOL_NT1) {
8080 req->flags2 |= 0x40; /* IS_LONG_NAME */
8081 SSVAL(req->inbuf,smb_flg2,req->flags2);
8084 if (conn->encrypt_level == Required && !req->encrypted) {
8085 if (state->call != TRANSACT2_QFSINFO &&
8086 state->call != TRANSACT2_SETFSINFO) {
8087 DEBUG(0,("handle_trans2: encryption required "
8088 "with call 0x%x\n",
8089 (unsigned int)state->call));
8090 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
8091 return;
8095 SMB_PERFCOUNT_SET_SUBOP(&req->pcd, state->call);
8097 /* Now we must call the relevant TRANS2 function */
8098 switch(state->call) {
8099 case TRANSACT2_OPEN:
8101 START_PROFILE(Trans2_open);
8102 call_trans2open(conn, req,
8103 &state->param, state->total_param,
8104 &state->data, state->total_data,
8105 state->max_data_return);
8106 END_PROFILE(Trans2_open);
8107 break;
8110 case TRANSACT2_FINDFIRST:
8112 START_PROFILE(Trans2_findfirst);
8113 call_trans2findfirst(conn, req,
8114 &state->param, state->total_param,
8115 &state->data, state->total_data,
8116 state->max_data_return);
8117 END_PROFILE(Trans2_findfirst);
8118 break;
8121 case TRANSACT2_FINDNEXT:
8123 START_PROFILE(Trans2_findnext);
8124 call_trans2findnext(conn, req,
8125 &state->param, state->total_param,
8126 &state->data, state->total_data,
8127 state->max_data_return);
8128 END_PROFILE(Trans2_findnext);
8129 break;
8132 case TRANSACT2_QFSINFO:
8134 START_PROFILE(Trans2_qfsinfo);
8135 call_trans2qfsinfo(conn, req,
8136 &state->param, state->total_param,
8137 &state->data, state->total_data,
8138 state->max_data_return);
8139 END_PROFILE(Trans2_qfsinfo);
8140 break;
8143 case TRANSACT2_SETFSINFO:
8145 START_PROFILE(Trans2_setfsinfo);
8146 call_trans2setfsinfo(conn, req,
8147 &state->param, state->total_param,
8148 &state->data, state->total_data,
8149 state->max_data_return);
8150 END_PROFILE(Trans2_setfsinfo);
8151 break;
8154 case TRANSACT2_QPATHINFO:
8155 case TRANSACT2_QFILEINFO:
8157 START_PROFILE(Trans2_qpathinfo);
8158 call_trans2qfilepathinfo(conn, req, state->call,
8159 &state->param, state->total_param,
8160 &state->data, state->total_data,
8161 state->max_data_return);
8162 END_PROFILE(Trans2_qpathinfo);
8163 break;
8166 case TRANSACT2_SETPATHINFO:
8167 case TRANSACT2_SETFILEINFO:
8169 START_PROFILE(Trans2_setpathinfo);
8170 call_trans2setfilepathinfo(conn, req, state->call,
8171 &state->param, state->total_param,
8172 &state->data, state->total_data,
8173 state->max_data_return);
8174 END_PROFILE(Trans2_setpathinfo);
8175 break;
8178 case TRANSACT2_FINDNOTIFYFIRST:
8180 START_PROFILE(Trans2_findnotifyfirst);
8181 call_trans2findnotifyfirst(conn, req,
8182 &state->param, state->total_param,
8183 &state->data, state->total_data,
8184 state->max_data_return);
8185 END_PROFILE(Trans2_findnotifyfirst);
8186 break;
8189 case TRANSACT2_FINDNOTIFYNEXT:
8191 START_PROFILE(Trans2_findnotifynext);
8192 call_trans2findnotifynext(conn, req,
8193 &state->param, state->total_param,
8194 &state->data, state->total_data,
8195 state->max_data_return);
8196 END_PROFILE(Trans2_findnotifynext);
8197 break;
8200 case TRANSACT2_MKDIR:
8202 START_PROFILE(Trans2_mkdir);
8203 call_trans2mkdir(conn, req,
8204 &state->param, state->total_param,
8205 &state->data, state->total_data,
8206 state->max_data_return);
8207 END_PROFILE(Trans2_mkdir);
8208 break;
8211 case TRANSACT2_GET_DFS_REFERRAL:
8213 START_PROFILE(Trans2_get_dfs_referral);
8214 call_trans2getdfsreferral(conn, req,
8215 &state->param, state->total_param,
8216 &state->data, state->total_data,
8217 state->max_data_return);
8218 END_PROFILE(Trans2_get_dfs_referral);
8219 break;
8222 case TRANSACT2_IOCTL:
8224 START_PROFILE(Trans2_ioctl);
8225 call_trans2ioctl(conn, req,
8226 &state->param, state->total_param,
8227 &state->data, state->total_data,
8228 state->max_data_return);
8229 END_PROFILE(Trans2_ioctl);
8230 break;
8233 default:
8234 /* Error in request */
8235 DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
8236 reply_doserror(req, ERRSRV,ERRerror);
8240 /****************************************************************************
8241 Reply to a SMBtrans2.
8242 ****************************************************************************/
8244 void reply_trans2(struct smb_request *req)
8246 connection_struct *conn = req->conn;
8247 unsigned int dsoff;
8248 unsigned int dscnt;
8249 unsigned int psoff;
8250 unsigned int pscnt;
8251 unsigned int tran_call;
8252 struct trans_state *state;
8253 NTSTATUS result;
8255 START_PROFILE(SMBtrans2);
8257 if (req->wct < 14) {
8258 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8259 END_PROFILE(SMBtrans2);
8260 return;
8263 dsoff = SVAL(req->vwv+12, 0);
8264 dscnt = SVAL(req->vwv+11, 0);
8265 psoff = SVAL(req->vwv+10, 0);
8266 pscnt = SVAL(req->vwv+9, 0);
8267 tran_call = SVAL(req->vwv+14, 0);
8269 result = allow_new_trans(conn->pending_trans, req->mid);
8270 if (!NT_STATUS_IS_OK(result)) {
8271 DEBUG(2, ("Got invalid trans2 request: %s\n",
8272 nt_errstr(result)));
8273 reply_nterror(req, result);
8274 END_PROFILE(SMBtrans2);
8275 return;
8278 if (IS_IPC(conn)) {
8279 switch (tran_call) {
8280 /* List the allowed trans2 calls on IPC$ */
8281 case TRANSACT2_OPEN:
8282 case TRANSACT2_GET_DFS_REFERRAL:
8283 case TRANSACT2_QFILEINFO:
8284 case TRANSACT2_QFSINFO:
8285 case TRANSACT2_SETFSINFO:
8286 break;
8287 default:
8288 reply_doserror(req, ERRSRV, ERRaccess);
8289 END_PROFILE(SMBtrans2);
8290 return;
8294 if ((state = TALLOC_P(conn, struct trans_state)) == NULL) {
8295 DEBUG(0, ("talloc failed\n"));
8296 reply_nterror(req, NT_STATUS_NO_MEMORY);
8297 END_PROFILE(SMBtrans2);
8298 return;
8301 state->cmd = SMBtrans2;
8303 state->mid = req->mid;
8304 state->vuid = req->vuid;
8305 state->setup_count = SVAL(req->vwv+13, 0);
8306 state->setup = NULL;
8307 state->total_param = SVAL(req->vwv+0, 0);
8308 state->param = NULL;
8309 state->total_data = SVAL(req->vwv+1, 0);
8310 state->data = NULL;
8311 state->max_param_return = SVAL(req->vwv+2, 0);
8312 state->max_data_return = SVAL(req->vwv+3, 0);
8313 state->max_setup_return = SVAL(req->vwv+4, 0);
8314 state->close_on_completion = BITSETW(req->vwv+5, 0);
8315 state->one_way = BITSETW(req->vwv+5, 1);
8317 state->call = tran_call;
8319 /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
8320 is so as a sanity check */
8321 if (state->setup_count != 1) {
8323 * Need to have rc=0 for ioctl to get job id for OS/2.
8324 * Network printing will fail if function is not successful.
8325 * Similar function in reply.c will be used if protocol
8326 * is LANMAN1.0 instead of LM1.2X002.
8327 * Until DosPrintSetJobInfo with PRJINFO3 is supported,
8328 * outbuf doesn't have to be set(only job id is used).
8330 if ( (state->setup_count == 4)
8331 && (tran_call == TRANSACT2_IOCTL)
8332 && (SVAL(req->vwv+16, 0) == LMCAT_SPL)
8333 && (SVAL(req->vwv+17, 0) == LMFUNC_GETJOBID)) {
8334 DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
8335 } else {
8336 DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
8337 DEBUG(2,("Transaction is %d\n",tran_call));
8338 TALLOC_FREE(state);
8339 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8340 END_PROFILE(SMBtrans2);
8341 return;
8345 if ((dscnt > state->total_data) || (pscnt > state->total_param))
8346 goto bad_param;
8348 if (state->total_data) {
8350 if (trans_oob(state->total_data, 0, dscnt)
8351 || trans_oob(smb_len(req->inbuf), dsoff, dscnt)) {
8352 goto bad_param;
8355 /* Can't use talloc here, the core routines do realloc on the
8356 * params and data. */
8357 state->data = (char *)SMB_MALLOC(state->total_data);
8358 if (state->data == NULL) {
8359 DEBUG(0,("reply_trans2: data malloc fail for %u "
8360 "bytes !\n", (unsigned int)state->total_data));
8361 TALLOC_FREE(state);
8362 reply_nterror(req, NT_STATUS_NO_MEMORY);
8363 END_PROFILE(SMBtrans2);
8364 return;
8367 memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
8370 if (state->total_param) {
8372 if (trans_oob(state->total_param, 0, pscnt)
8373 || trans_oob(smb_len(req->inbuf), psoff, pscnt)) {
8374 goto bad_param;
8377 /* Can't use talloc here, the core routines do realloc on the
8378 * params and data. */
8379 state->param = (char *)SMB_MALLOC(state->total_param);
8380 if (state->param == NULL) {
8381 DEBUG(0,("reply_trans: param malloc fail for %u "
8382 "bytes !\n", (unsigned int)state->total_param));
8383 SAFE_FREE(state->data);
8384 TALLOC_FREE(state);
8385 reply_nterror(req, NT_STATUS_NO_MEMORY);
8386 END_PROFILE(SMBtrans2);
8387 return;
8390 memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
8393 state->received_data = dscnt;
8394 state->received_param = pscnt;
8396 if ((state->received_param == state->total_param) &&
8397 (state->received_data == state->total_data)) {
8399 handle_trans2(conn, req, state);
8401 SAFE_FREE(state->data);
8402 SAFE_FREE(state->param);
8403 TALLOC_FREE(state);
8404 END_PROFILE(SMBtrans2);
8405 return;
8408 DLIST_ADD(conn->pending_trans, state);
8410 /* We need to send an interim response then receive the rest
8411 of the parameter/data bytes */
8412 reply_outbuf(req, 0, 0);
8413 show_msg((char *)req->outbuf);
8414 END_PROFILE(SMBtrans2);
8415 return;
8417 bad_param:
8419 DEBUG(0,("reply_trans2: invalid trans parameters\n"));
8420 SAFE_FREE(state->data);
8421 SAFE_FREE(state->param);
8422 TALLOC_FREE(state);
8423 END_PROFILE(SMBtrans2);
8424 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8428 /****************************************************************************
8429 Reply to a SMBtranss2
8430 ****************************************************************************/
8432 void reply_transs2(struct smb_request *req)
8434 connection_struct *conn = req->conn;
8435 unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
8436 struct trans_state *state;
8438 START_PROFILE(SMBtranss2);
8440 show_msg((char *)req->inbuf);
8442 if (req->wct < 8) {
8443 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8444 END_PROFILE(SMBtranss2);
8445 return;
8448 for (state = conn->pending_trans; state != NULL;
8449 state = state->next) {
8450 if (state->mid == req->mid) {
8451 break;
8455 if ((state == NULL) || (state->cmd != SMBtrans2)) {
8456 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8457 END_PROFILE(SMBtranss2);
8458 return;
8461 /* Revise state->total_param and state->total_data in case they have
8462 changed downwards */
8464 if (SVAL(req->vwv+0, 0) < state->total_param)
8465 state->total_param = SVAL(req->vwv+0, 0);
8466 if (SVAL(req->vwv+1, 0) < state->total_data)
8467 state->total_data = SVAL(req->vwv+1, 0);
8469 pcnt = SVAL(req->vwv+2, 0);
8470 poff = SVAL(req->vwv+3, 0);
8471 pdisp = SVAL(req->vwv+4, 0);
8473 dcnt = SVAL(req->vwv+5, 0);
8474 doff = SVAL(req->vwv+6, 0);
8475 ddisp = SVAL(req->vwv+7, 0);
8477 state->received_param += pcnt;
8478 state->received_data += dcnt;
8480 if ((state->received_data > state->total_data) ||
8481 (state->received_param > state->total_param))
8482 goto bad_param;
8484 if (pcnt) {
8485 if (trans_oob(state->total_param, pdisp, pcnt)
8486 || trans_oob(smb_len(req->inbuf), poff, pcnt)) {
8487 goto bad_param;
8489 memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
8492 if (dcnt) {
8493 if (trans_oob(state->total_data, ddisp, dcnt)
8494 || trans_oob(smb_len(req->inbuf), doff, dcnt)) {
8495 goto bad_param;
8497 memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
8500 if ((state->received_param < state->total_param) ||
8501 (state->received_data < state->total_data)) {
8502 END_PROFILE(SMBtranss2);
8503 return;
8506 handle_trans2(conn, req, state);
8508 DLIST_REMOVE(conn->pending_trans, state);
8509 SAFE_FREE(state->data);
8510 SAFE_FREE(state->param);
8511 TALLOC_FREE(state);
8513 END_PROFILE(SMBtranss2);
8514 return;
8516 bad_param:
8518 DEBUG(0,("reply_transs2: invalid trans parameters\n"));
8519 DLIST_REMOVE(conn->pending_trans, state);
8520 SAFE_FREE(state->data);
8521 SAFE_FREE(state->param);
8522 TALLOC_FREE(state);
8523 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
8524 END_PROFILE(SMBtranss2);
8525 return;