Line data Source code
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
9 :
10 : Extensively modified by Andrew Tridgell, 1995
11 :
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.
16 :
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.
21 :
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/>.
24 : */
25 :
26 : #include "includes.h"
27 : #include "ntioctl.h"
28 : #include "system/filesys.h"
29 : #include "lib/util/time_basic.h"
30 : #include "version.h"
31 : #include "smbd/smbd.h"
32 : #include "smbd/globals.h"
33 : #include "../libcli/auth/libcli_auth.h"
34 : #include "../librpc/gen_ndr/xattr.h"
35 : #include "../librpc/gen_ndr/ndr_security.h"
36 : #include "libcli/security/security.h"
37 : #include "trans2.h"
38 : #include "auth.h"
39 : #include "smbprofile.h"
40 : #include "rpc_server/srv_pipe_hnd.h"
41 : #include "printing.h"
42 : #include "lib/util_ea.h"
43 : #include "lib/readdir_attr.h"
44 : #include "messages.h"
45 : #include "libcli/smb/smb2_posix.h"
46 : #include "lib/util/string_wrappers.h"
47 : #include "source3/lib/substitute.h"
48 : #include "source3/lib/adouble.h"
49 :
50 : #define DIR_ENTRY_SAFETY_MARGIN 4096
51 :
52 : static char *store_file_unix_basic(connection_struct *conn,
53 : char *pdata,
54 : files_struct *fsp,
55 : const SMB_STRUCT_STAT *psbuf);
56 :
57 : static char *store_file_unix_basic_info2(connection_struct *conn,
58 : char *pdata,
59 : files_struct *fsp,
60 : const SMB_STRUCT_STAT *psbuf);
61 :
62 : static uint32_t generate_volume_serial_number(
63 : const struct loadparm_substitution *lp_sub,
64 : int snum);
65 :
66 : /****************************************************************************
67 : Check if an open file handle is a symlink.
68 : ****************************************************************************/
69 :
70 464 : NTSTATUS refuse_symlink_fsp(const files_struct *fsp)
71 : {
72 :
73 464 : if (!VALID_STAT(fsp->fsp_name->st)) {
74 0 : return NT_STATUS_ACCESS_DENIED;
75 : }
76 464 : if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
77 0 : return NT_STATUS_ACCESS_DENIED;
78 : }
79 464 : if (fsp_get_pathref_fd(fsp) == -1) {
80 0 : return NT_STATUS_ACCESS_DENIED;
81 : }
82 464 : return NT_STATUS_OK;
83 : }
84 :
85 64 : NTSTATUS check_access_fsp(struct files_struct *fsp,
86 : uint32_t access_mask)
87 : {
88 64 : if (!fsp->fsp_flags.is_fsa) {
89 0 : return smbd_check_access_rights_fsp(fsp->conn->cwd_fsp,
90 : fsp,
91 : false,
92 : access_mask);
93 : }
94 64 : if (!(fsp->access_mask & access_mask)) {
95 0 : return NT_STATUS_ACCESS_DENIED;
96 : }
97 64 : return NT_STATUS_OK;
98 : }
99 :
100 : #if defined(HAVE_POSIX_ACLS)
101 : /****************************************************************************
102 : Utility function to open a fsp for a POSIX handle operation.
103 : ****************************************************************************/
104 :
105 0 : static NTSTATUS get_posix_fsp(connection_struct *conn,
106 : struct smb_request *req,
107 : struct smb_filename *smb_fname,
108 : uint32_t access_mask,
109 : files_struct **ret_fsp)
110 : {
111 : NTSTATUS status;
112 0 : uint32_t create_disposition = FILE_OPEN;
113 0 : uint32_t share_access = FILE_SHARE_READ|
114 : FILE_SHARE_WRITE|
115 : FILE_SHARE_DELETE;
116 0 : struct smb2_create_blobs *posx = NULL;
117 :
118 : /*
119 : * Only FILE_FLAG_POSIX_SEMANTICS matters on existing files,
120 : * but set reasonable defaults.
121 : */
122 0 : uint32_t file_attributes = 0664;
123 0 : uint32_t oplock = NO_OPLOCK;
124 0 : uint32_t create_options = FILE_NON_DIRECTORY_FILE;
125 :
126 : /* File or directory must exist. */
127 0 : if (!VALID_STAT(smb_fname->st)) {
128 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
129 : }
130 : /* Cannot be a symlink. */
131 0 : if (S_ISLNK(smb_fname->st.st_ex_mode)) {
132 0 : return NT_STATUS_ACCESS_DENIED;
133 : }
134 : /* Set options correctly for directory open. */
135 0 : if (S_ISDIR(smb_fname->st.st_ex_mode)) {
136 : /*
137 : * Only FILE_FLAG_POSIX_SEMANTICS matters on existing
138 : * directories, but set reasonable defaults.
139 : */
140 0 : file_attributes = 0775;
141 0 : create_options = FILE_DIRECTORY_FILE;
142 : }
143 :
144 0 : status = make_smb2_posix_create_ctx(
145 : talloc_tos(), &posx, file_attributes);
146 0 : if (!NT_STATUS_IS_OK(status)) {
147 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
148 : nt_errstr(status));
149 0 : goto done;
150 : }
151 :
152 0 : status = SMB_VFS_CREATE_FILE(
153 : conn, /* conn */
154 : req, /* req */
155 : NULL, /* dirfsp */
156 : smb_fname, /* fname */
157 : access_mask, /* access_mask */
158 : share_access, /* share_access */
159 : create_disposition,/* create_disposition*/
160 : create_options, /* create_options */
161 : file_attributes,/* file_attributes */
162 : oplock, /* oplock_request */
163 : NULL, /* lease */
164 : 0, /* allocation_size */
165 : 0, /* private_flags */
166 : NULL, /* sd */
167 : NULL, /* ea_list */
168 : ret_fsp, /* result */
169 : NULL, /* pinfo */
170 : posx, /* in_context */
171 : NULL); /* out_context */
172 :
173 0 : done:
174 0 : TALLOC_FREE(posx);
175 0 : return status;
176 : }
177 : #endif
178 :
179 : /********************************************************************
180 : Roundup a value to the nearest allocation roundup size boundary.
181 : Only do this for Windows clients.
182 : ********************************************************************/
183 :
184 9637 : uint64_t smb_roundup(connection_struct *conn, uint64_t val)
185 : {
186 9637 : uint64_t rval = lp_allocation_roundup_size(SNUM(conn));
187 :
188 : /* Only roundup for Windows clients. */
189 9637 : enum remote_arch_types ra_type = get_remote_arch();
190 9637 : if (rval && (ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
191 0 : val = SMB_ROUNDUP(val,rval);
192 : }
193 9637 : return val;
194 : }
195 :
196 : /****************************************************************************
197 : Utility functions for dealing with extended attributes.
198 : ****************************************************************************/
199 :
200 : /****************************************************************************
201 : Refuse to allow clients to overwrite our private xattrs.
202 : ****************************************************************************/
203 :
204 4543 : bool samba_private_attr_name(const char *unix_ea_name)
205 : {
206 : static const char * const prohibited_ea_names[] = {
207 : SAMBA_POSIX_INHERITANCE_EA_NAME,
208 : SAMBA_XATTR_DOS_ATTRIB,
209 : SAMBA_XATTR_MARKER,
210 : XATTR_NTACL_NAME,
211 : AFPINFO_EA_NETATALK,
212 : NULL
213 : };
214 :
215 : int i;
216 :
217 9630 : for (i = 0; prohibited_ea_names[i]; i++) {
218 9601 : if (strequal( prohibited_ea_names[i], unix_ea_name))
219 4514 : return true;
220 : }
221 29 : if (strncasecmp_m(unix_ea_name, SAMBA_XATTR_DOSSTREAM_PREFIX,
222 : strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) == 0) {
223 24 : return true;
224 : }
225 5 : return false;
226 : }
227 :
228 : /****************************************************************************
229 : Get one EA value. Fill in a struct ea_struct.
230 : ****************************************************************************/
231 :
232 79 : NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx,
233 : files_struct *fsp,
234 : const char *ea_name,
235 : struct ea_struct *pea)
236 : {
237 : /* Get the value of this xattr. Max size is 64k. */
238 79 : size_t attr_size = 256;
239 79 : char *val = NULL;
240 : ssize_t sizeret;
241 79 : size_t max_xattr_size = 0;
242 :
243 79 : if (fsp == NULL) {
244 0 : return NT_STATUS_INVALID_HANDLE;
245 : }
246 :
247 79 : max_xattr_size = lp_smbd_max_xattr_size(SNUM(fsp->conn));
248 :
249 79 : again:
250 :
251 79 : val = talloc_realloc(mem_ctx, val, char, attr_size);
252 79 : if (!val) {
253 0 : return NT_STATUS_NO_MEMORY;
254 : }
255 :
256 79 : sizeret = SMB_VFS_FGETXATTR(fsp, ea_name, val, attr_size);
257 79 : if (sizeret == -1 && errno == ERANGE && attr_size < max_xattr_size) {
258 0 : attr_size = max_xattr_size;
259 0 : goto again;
260 : }
261 :
262 79 : if (sizeret == -1) {
263 8 : return map_nt_error_from_unix(errno);
264 : }
265 :
266 71 : DEBUG(10,("get_ea_value: EA %s is of length %u\n", ea_name, (unsigned int)sizeret));
267 71 : dump_data(10, (uint8_t *)val, sizeret);
268 :
269 71 : pea->flags = 0;
270 71 : if (strnequal(ea_name, "user.", 5)) {
271 71 : pea->name = talloc_strdup(mem_ctx, &ea_name[5]);
272 : } else {
273 0 : pea->name = talloc_strdup(mem_ctx, ea_name);
274 : }
275 71 : if (pea->name == NULL) {
276 0 : TALLOC_FREE(val);
277 0 : return NT_STATUS_NO_MEMORY;
278 : }
279 71 : pea->value.data = (unsigned char *)val;
280 71 : pea->value.length = (size_t)sizeret;
281 71 : return NT_STATUS_OK;
282 : }
283 :
284 10360 : NTSTATUS get_ea_names_from_fsp(TALLOC_CTX *mem_ctx,
285 : files_struct *fsp,
286 : char ***pnames,
287 : size_t *pnum_names)
288 : {
289 : char smallbuf[1024];
290 : /* Get a list of all xattrs. Max namesize is 64k. */
291 10360 : size_t ea_namelist_size = 1024;
292 10360 : char *ea_namelist = smallbuf;
293 10360 : char *to_free = NULL;
294 :
295 : char *p;
296 : char **names;
297 : size_t num_names;
298 10360 : ssize_t sizeret = -1;
299 : NTSTATUS status;
300 :
301 10360 : if (pnames) {
302 10360 : *pnames = NULL;
303 : }
304 10360 : *pnum_names = 0;
305 :
306 10360 : if (fsp == NULL) {
307 : /*
308 : * Callers may pass fsp == NULL when passing smb_fname->fsp of a
309 : * symlink. This is ok, handle it here, by just return no EA's
310 : * on a symlink.
311 : */
312 0 : return NT_STATUS_OK;
313 : }
314 :
315 : /* should be the case that fsp != NULL */
316 10360 : SMB_ASSERT(fsp != NULL);
317 :
318 10360 : sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
319 : ea_namelist_size);
320 :
321 10360 : if ((sizeret == -1) && (errno == ERANGE)) {
322 0 : ea_namelist_size = 65536;
323 0 : ea_namelist = talloc_array(mem_ctx, char, ea_namelist_size);
324 0 : if (ea_namelist == NULL) {
325 0 : return NT_STATUS_NO_MEMORY;
326 : }
327 0 : to_free = ea_namelist;
328 :
329 0 : sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
330 : ea_namelist_size);
331 : }
332 :
333 10360 : if (sizeret == -1) {
334 0 : status = map_nt_error_from_unix(errno);
335 0 : TALLOC_FREE(to_free);
336 0 : return status;
337 : }
338 :
339 10360 : DBG_DEBUG("ea_namelist size = %zd\n", sizeret);
340 :
341 10360 : if (sizeret == 0) {
342 5338 : TALLOC_FREE(to_free);
343 5338 : return NT_STATUS_OK;
344 : }
345 :
346 : /*
347 : * Ensure the result is 0-terminated
348 : */
349 :
350 5022 : if (ea_namelist[sizeret-1] != '\0') {
351 0 : TALLOC_FREE(to_free);
352 0 : return NT_STATUS_INTERNAL_ERROR;
353 : }
354 :
355 : /*
356 : * count the names
357 : */
358 5022 : num_names = 0;
359 :
360 26875 : for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
361 21853 : num_names += 1;
362 : }
363 :
364 5022 : *pnum_names = num_names;
365 :
366 5022 : if (pnames == NULL) {
367 0 : TALLOC_FREE(to_free);
368 0 : return NT_STATUS_OK;
369 : }
370 :
371 5022 : names = talloc_array(mem_ctx, char *, num_names);
372 5022 : if (names == NULL) {
373 0 : DEBUG(0, ("talloc failed\n"));
374 0 : TALLOC_FREE(to_free);
375 0 : return NT_STATUS_NO_MEMORY;
376 : }
377 :
378 5022 : if (ea_namelist == smallbuf) {
379 5022 : ea_namelist = talloc_memdup(names, smallbuf, sizeret);
380 5022 : if (ea_namelist == NULL) {
381 0 : TALLOC_FREE(names);
382 0 : return NT_STATUS_NO_MEMORY;
383 : }
384 : } else {
385 0 : talloc_steal(names, ea_namelist);
386 :
387 0 : ea_namelist = talloc_realloc(names, ea_namelist, char,
388 : sizeret);
389 0 : if (ea_namelist == NULL) {
390 0 : TALLOC_FREE(names);
391 0 : return NT_STATUS_NO_MEMORY;
392 : }
393 : }
394 :
395 5022 : num_names = 0;
396 :
397 26875 : for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
398 21853 : names[num_names++] = p;
399 : }
400 :
401 5022 : *pnames = names;
402 :
403 5022 : return NT_STATUS_OK;
404 : }
405 :
406 : /****************************************************************************
407 : Return a linked list of the total EA's. Plus the total size
408 : ****************************************************************************/
409 :
410 10348 : static NTSTATUS get_ea_list_from_fsp(TALLOC_CTX *mem_ctx,
411 : files_struct *fsp,
412 : size_t *pea_total_len,
413 : struct ea_list **ea_list)
414 : {
415 : /* Get a list of all xattrs. Max namesize is 64k. */
416 : size_t i, num_names;
417 : char **names;
418 10348 : struct ea_list *ea_list_head = NULL;
419 10348 : bool posix_pathnames = false;
420 : NTSTATUS status;
421 :
422 10348 : *pea_total_len = 0;
423 10348 : *ea_list = NULL;
424 :
425 : /* symlink */
426 10348 : if (fsp == NULL) {
427 0 : return NT_STATUS_OK;
428 : }
429 :
430 10348 : if (!lp_ea_support(SNUM(fsp->conn))) {
431 0 : return NT_STATUS_OK;
432 : }
433 :
434 10348 : if (fsp_is_alternate_stream(fsp)) {
435 0 : return NT_STATUS_INVALID_PARAMETER;
436 : }
437 :
438 10348 : posix_pathnames = (fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH);
439 :
440 10348 : status = get_ea_names_from_fsp(talloc_tos(),
441 : fsp,
442 : &names,
443 : &num_names);
444 :
445 10348 : if (!NT_STATUS_IS_OK(status)) {
446 0 : return status;
447 : }
448 :
449 10348 : if (num_names == 0) {
450 5338 : return NT_STATUS_OK;
451 : }
452 :
453 26843 : for (i=0; i<num_names; i++) {
454 : struct ea_list *listp;
455 : fstring dos_ea_name;
456 :
457 : /*
458 : * POSIX EA names are divided into several namespaces by
459 : * means of string prefixes. Usually, the system controls
460 : * semantics for each namespace, but the 'user' namespace is
461 : * available for arbitrary use, which comes closest to
462 : * Windows EA semantics. Hence, we map POSIX EAs from the
463 : * 'user' namespace to Windows EAs, and just ignore all the
464 : * other namespaces. Also, a few specific names in the 'user'
465 : * namespace are used by Samba internally. Filter them out as
466 : * well, and only present the EAs that are available for
467 : * arbitrary use.
468 : */
469 21833 : if (!strnequal(names[i], "user.", 5)
470 4529 : || samba_private_attr_name(names[i]))
471 41652 : continue;
472 :
473 : /*
474 : * Filter out any underlying POSIX EA names
475 : * that a Windows client can't handle.
476 : */
477 6 : if (!posix_pathnames &&
478 3 : is_invalid_windows_ea_name(names[i])) {
479 0 : continue;
480 : }
481 :
482 3 : listp = talloc(mem_ctx, struct ea_list);
483 3 : if (listp == NULL) {
484 0 : return NT_STATUS_NO_MEMORY;
485 : }
486 :
487 6 : status = get_ea_value_fsp(listp,
488 : fsp,
489 3 : names[i],
490 : &listp->ea);
491 :
492 3 : if (!NT_STATUS_IS_OK(status)) {
493 0 : TALLOC_FREE(listp);
494 0 : return status;
495 : }
496 :
497 3 : if (listp->ea.value.length == 0) {
498 : /*
499 : * We can never return a zero length EA.
500 : * Windows reports the EA's as corrupted.
501 : */
502 0 : TALLOC_FREE(listp);
503 0 : continue;
504 3 : } else if (listp->ea.value.length > 65536) {
505 : /*
506 : * SMB clients may report error with file
507 : * if large EA is presented to them.
508 : */
509 0 : DBG_ERR("EA [%s] on file [%s] exceeds "
510 : "maximum permitted EA size of 64KiB: %zu\n.",
511 : listp->ea.name, fsp_str_dbg(fsp),
512 : listp->ea.value.length);
513 0 : TALLOC_FREE(listp);
514 0 : continue;
515 : }
516 :
517 3 : push_ascii_fstring(dos_ea_name, listp->ea.name);
518 :
519 6 : *pea_total_len +=
520 3 : 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
521 :
522 3 : DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len "
523 : "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
524 : (unsigned int)listp->ea.value.length));
525 :
526 3 : DLIST_ADD_END(ea_list_head, listp);
527 :
528 : }
529 :
530 : /* Add on 4 for total length. */
531 5010 : if (*pea_total_len) {
532 2 : *pea_total_len += 4;
533 : }
534 :
535 5010 : DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
536 : (unsigned int)*pea_total_len));
537 :
538 5010 : *ea_list = ea_list_head;
539 5010 : return NT_STATUS_OK;
540 : }
541 :
542 : /****************************************************************************
543 : Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer
544 : that was filled.
545 : ****************************************************************************/
546 :
547 0 : static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
548 : connection_struct *conn, struct ea_list *ea_list)
549 : {
550 0 : unsigned int ret_data_size = 4;
551 0 : char *p = pdata;
552 :
553 0 : SMB_ASSERT(total_data_size >= 4);
554 :
555 0 : if (!lp_ea_support(SNUM(conn))) {
556 0 : SIVAL(pdata,4,0);
557 0 : return 4;
558 : }
559 :
560 0 : for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
561 : size_t dos_namelen;
562 : fstring dos_ea_name;
563 0 : push_ascii_fstring(dos_ea_name, ea_list->ea.name);
564 0 : dos_namelen = strlen(dos_ea_name);
565 0 : if (dos_namelen > 255 || dos_namelen == 0) {
566 : break;
567 : }
568 0 : if (ea_list->ea.value.length > 65535) {
569 0 : break;
570 : }
571 0 : if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
572 0 : break;
573 : }
574 :
575 : /* We know we have room. */
576 0 : SCVAL(p,0,ea_list->ea.flags);
577 0 : SCVAL(p,1,dos_namelen);
578 0 : SSVAL(p,2,ea_list->ea.value.length);
579 0 : strlcpy(p+4, dos_ea_name, dos_namelen+1);
580 0 : if (ea_list->ea.value.length > 0) {
581 0 : memcpy(p + 4 + dos_namelen + 1,
582 0 : ea_list->ea.value.data,
583 : ea_list->ea.value.length);
584 : }
585 :
586 0 : total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
587 0 : p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
588 : }
589 :
590 0 : ret_data_size = PTR_DIFF(p, pdata);
591 0 : DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
592 0 : SIVAL(pdata,0,ret_data_size);
593 0 : return ret_data_size;
594 : }
595 :
596 10346 : static NTSTATUS fill_ea_chained_buffer(TALLOC_CTX *mem_ctx,
597 : char *pdata,
598 : unsigned int total_data_size,
599 : unsigned int *ret_data_size,
600 : connection_struct *conn,
601 : struct ea_list *ea_list)
602 : {
603 10346 : uint8_t *p = (uint8_t *)pdata;
604 10346 : uint8_t *last_start = NULL;
605 10346 : bool do_store_data = (pdata != NULL);
606 :
607 10346 : *ret_data_size = 0;
608 :
609 10346 : if (!lp_ea_support(SNUM(conn))) {
610 0 : return NT_STATUS_NO_EAS_ON_FILE;
611 : }
612 :
613 17781 : for (; ea_list; ea_list = ea_list->next) {
614 : size_t dos_namelen;
615 : fstring dos_ea_name;
616 : size_t this_size;
617 2 : size_t pad = 0;
618 :
619 2 : if (last_start != NULL && do_store_data) {
620 0 : SIVAL(last_start, 0, PTR_DIFF(p, last_start));
621 : }
622 2 : last_start = p;
623 :
624 2 : push_ascii_fstring(dos_ea_name, ea_list->ea.name);
625 2 : dos_namelen = strlen(dos_ea_name);
626 2 : if (dos_namelen > 255 || dos_namelen == 0) {
627 0 : return NT_STATUS_INTERNAL_ERROR;
628 : }
629 2 : if (ea_list->ea.value.length > 65535) {
630 0 : return NT_STATUS_INTERNAL_ERROR;
631 : }
632 :
633 2 : this_size = 0x08 + dos_namelen + 1 + ea_list->ea.value.length;
634 :
635 2 : if (ea_list->next) {
636 1 : pad = (4 - (this_size % 4)) % 4;
637 1 : this_size += pad;
638 : }
639 :
640 2 : if (do_store_data) {
641 0 : if (this_size > total_data_size) {
642 0 : return NT_STATUS_INFO_LENGTH_MISMATCH;
643 : }
644 :
645 : /* We know we have room. */
646 0 : SIVAL(p, 0x00, 0); /* next offset */
647 0 : SCVAL(p, 0x04, ea_list->ea.flags);
648 0 : SCVAL(p, 0x05, dos_namelen);
649 0 : SSVAL(p, 0x06, ea_list->ea.value.length);
650 0 : strlcpy((char *)(p+0x08), dos_ea_name, dos_namelen+1);
651 0 : memcpy(p + 0x08 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
652 0 : if (pad) {
653 0 : memset(p + 0x08 + dos_namelen + 1 + ea_list->ea.value.length,
654 : '\0',
655 : pad);
656 : }
657 0 : total_data_size -= this_size;
658 : }
659 :
660 2 : p += this_size;
661 : }
662 :
663 10346 : *ret_data_size = PTR_DIFF(p, pdata);
664 10346 : DEBUG(10,("fill_ea_chained_buffer: data_size = %u\n", *ret_data_size));
665 10346 : return NT_STATUS_OK;
666 : }
667 :
668 10768 : unsigned int estimate_ea_size(files_struct *fsp)
669 : {
670 10768 : size_t total_ea_len = 0;
671 : TALLOC_CTX *mem_ctx;
672 10768 : struct ea_list *ea_list = NULL;
673 : NTSTATUS status;
674 :
675 : /* symlink */
676 10768 : if (fsp == NULL) {
677 422 : return 0;
678 : }
679 :
680 10346 : if (!lp_ea_support(SNUM(fsp->conn))) {
681 0 : return 0;
682 : }
683 :
684 10346 : mem_ctx = talloc_stackframe();
685 :
686 : /* If this is a stream fsp, then we need to instead find the
687 : * estimated ea len from the main file, not the stream
688 : * (streams cannot have EAs), but the estimate isn't just 0 in
689 : * this case! */
690 10346 : fsp = metadata_fsp(fsp);
691 10346 : (void)get_ea_list_from_fsp(mem_ctx,
692 : fsp,
693 : &total_ea_len,
694 : &ea_list);
695 :
696 10346 : if(fsp->conn->sconn->using_smb2) {
697 : unsigned int ret_data_size;
698 : /*
699 : * We're going to be using fill_ea_chained_buffer() to
700 : * marshall EA's - this size is significantly larger
701 : * than the SMB1 buffer. Re-calculate the size without
702 : * marshalling.
703 : */
704 17777 : status = fill_ea_chained_buffer(mem_ctx,
705 : NULL,
706 : 0,
707 : &ret_data_size,
708 10346 : fsp->conn,
709 : ea_list);
710 10346 : if (!NT_STATUS_IS_OK(status)) {
711 0 : ret_data_size = 0;
712 : }
713 10346 : total_ea_len = ret_data_size;
714 : }
715 10346 : TALLOC_FREE(mem_ctx);
716 10346 : return total_ea_len;
717 : }
718 :
719 : /****************************************************************************
720 : Ensure the EA name is case insensitive by matching any existing EA name.
721 : ****************************************************************************/
722 :
723 2 : static void canonicalize_ea_name(files_struct *fsp,
724 : fstring unix_ea_name)
725 : {
726 : size_t total_ea_len;
727 2 : TALLOC_CTX *mem_ctx = talloc_tos();
728 : struct ea_list *ea_list;
729 2 : NTSTATUS status = get_ea_list_from_fsp(mem_ctx,
730 : fsp,
731 : &total_ea_len,
732 : &ea_list);
733 2 : if (!NT_STATUS_IS_OK(status)) {
734 0 : return;
735 : }
736 :
737 3 : for (; ea_list; ea_list = ea_list->next) {
738 1 : if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
739 0 : DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
740 : &unix_ea_name[5], ea_list->ea.name));
741 0 : strlcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-5);
742 0 : break;
743 : }
744 : }
745 : }
746 :
747 : /****************************************************************************
748 : Set or delete an extended attribute.
749 : ****************************************************************************/
750 :
751 1 : NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
752 : struct ea_list *ea_list)
753 : {
754 : NTSTATUS status;
755 1 : bool posix_pathnames = false;
756 :
757 1 : if (!lp_ea_support(SNUM(conn))) {
758 0 : return NT_STATUS_EAS_NOT_SUPPORTED;
759 : }
760 :
761 1 : if (fsp == NULL) {
762 0 : return NT_STATUS_INVALID_HANDLE;
763 : }
764 :
765 1 : posix_pathnames = (fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH);
766 :
767 1 : status = refuse_symlink_fsp(fsp);
768 1 : if (!NT_STATUS_IS_OK(status)) {
769 0 : return status;
770 : }
771 :
772 1 : status = check_access_fsp(fsp, FILE_WRITE_EA);
773 1 : if (!NT_STATUS_IS_OK(status)) {
774 0 : return status;
775 : }
776 :
777 : /* Setting EAs on streams isn't supported. */
778 1 : if (fsp_is_alternate_stream(fsp)) {
779 0 : return NT_STATUS_INVALID_PARAMETER;
780 : }
781 :
782 : /*
783 : * Filter out invalid Windows EA names - before
784 : * we set *any* of them.
785 : */
786 :
787 1 : if (!posix_pathnames && ea_list_has_invalid_name(ea_list)) {
788 0 : return STATUS_INVALID_EA_NAME;
789 : }
790 :
791 6 : for (;ea_list; ea_list = ea_list->next) {
792 : int ret;
793 : fstring unix_ea_name;
794 :
795 : /*
796 : * Complementing the forward mapping from POSIX EAs to
797 : * Windows EAs in get_ea_list_from_fsp(), here we map in the
798 : * opposite direction from Windows EAs to the 'user' namespace
799 : * of POSIX EAs. Hence, all POSIX EA names the we set here must
800 : * start with a 'user.' prefix.
801 : */
802 2 : fstrcpy(unix_ea_name, "user.");
803 2 : fstrcat(unix_ea_name, ea_list->ea.name);
804 :
805 2 : canonicalize_ea_name(fsp, unix_ea_name);
806 :
807 2 : DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
808 :
809 2 : if (samba_private_attr_name(unix_ea_name)) {
810 0 : DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
811 0 : return NT_STATUS_ACCESS_DENIED;
812 : }
813 :
814 2 : if (ea_list->ea.value.length == 0) {
815 : /* Remove the attribute. */
816 0 : DBG_DEBUG("deleting ea name %s on "
817 : "file %s by file descriptor.\n",
818 : unix_ea_name, fsp_str_dbg(fsp));
819 0 : ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name);
820 : #ifdef ENOATTR
821 : /* Removing a non existent attribute always succeeds. */
822 0 : if (ret == -1 && errno == ENOATTR) {
823 0 : DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",
824 : unix_ea_name));
825 0 : ret = 0;
826 : }
827 : #endif
828 : } else {
829 2 : DEBUG(10,("set_ea: setting ea name %s on file "
830 : "%s by file descriptor.\n",
831 : unix_ea_name, fsp_str_dbg(fsp)));
832 2 : ret = SMB_VFS_FSETXATTR(fsp, unix_ea_name,
833 : ea_list->ea.value.data, ea_list->ea.value.length, 0);
834 : }
835 :
836 2 : if (ret == -1) {
837 : #ifdef ENOTSUP
838 0 : if (errno == ENOTSUP) {
839 0 : return NT_STATUS_EAS_NOT_SUPPORTED;
840 : }
841 : #endif
842 0 : return map_nt_error_from_unix(errno);
843 : }
844 :
845 : }
846 1 : return NT_STATUS_OK;
847 : }
848 :
849 : /****************************************************************************
850 : Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
851 : ****************************************************************************/
852 :
853 0 : struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
854 : {
855 0 : struct ea_list *ea_list_head = NULL;
856 0 : size_t offset = 0;
857 0 : size_t bytes_used = 0;
858 :
859 0 : while (offset < data_size) {
860 0 : struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);
861 :
862 0 : if (!eal) {
863 0 : return NULL;
864 : }
865 :
866 0 : DLIST_ADD_END(ea_list_head, eal);
867 0 : offset += bytes_used;
868 : }
869 :
870 0 : return ea_list_head;
871 : }
872 :
873 : /****************************************************************************
874 : Count the total EA size needed.
875 : ****************************************************************************/
876 :
877 0 : static size_t ea_list_size(struct ea_list *ealist)
878 : {
879 : fstring dos_ea_name;
880 : struct ea_list *listp;
881 0 : size_t ret = 0;
882 :
883 0 : for (listp = ealist; listp; listp = listp->next) {
884 0 : push_ascii_fstring(dos_ea_name, listp->ea.name);
885 0 : ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
886 : }
887 : /* Add on 4 for total length. */
888 0 : if (ret) {
889 0 : ret += 4;
890 : }
891 :
892 0 : return ret;
893 : }
894 :
895 : /****************************************************************************
896 : Return a union of EA's from a file list and a list of names.
897 : The TALLOC context for the two lists *MUST* be identical as we steal
898 : memory from one list to add to another. JRA.
899 : ****************************************************************************/
900 :
901 0 : static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *file_list, size_t *total_ea_len)
902 : {
903 : struct ea_list *nlistp, *flistp;
904 :
905 0 : for (nlistp = name_list; nlistp; nlistp = nlistp->next) {
906 0 : for (flistp = file_list; flistp; flistp = flistp->next) {
907 0 : if (strequal(nlistp->ea.name, flistp->ea.name)) {
908 0 : break;
909 : }
910 : }
911 :
912 0 : if (flistp) {
913 : /* Copy the data from this entry. */
914 0 : nlistp->ea.flags = flistp->ea.flags;
915 0 : nlistp->ea.value = flistp->ea.value;
916 : } else {
917 : /* Null entry. */
918 0 : nlistp->ea.flags = 0;
919 0 : ZERO_STRUCT(nlistp->ea.value);
920 : }
921 : }
922 :
923 0 : *total_ea_len = ea_list_size(name_list);
924 0 : return name_list;
925 : }
926 :
927 : /*********************************************************
928 : Routine to check if a given string matches exactly.
929 : as a special case a mask of "." does NOT match. That
930 : is required for correct wildcard semantics
931 : Case can be significant or not.
932 : **********************************************************/
933 :
934 11827 : static bool exact_match(bool has_wild,
935 : bool case_sensitive,
936 : const char *str,
937 : const char *mask)
938 : {
939 11827 : if (mask[0] == '.' && mask[1] == 0) {
940 0 : return false;
941 : }
942 :
943 11827 : if (has_wild) {
944 10562 : return false;
945 : }
946 :
947 1265 : if (case_sensitive) {
948 0 : return strcmp(str,mask)==0;
949 : } else {
950 1265 : return strcasecmp_m(str,mask) == 0;
951 : }
952 : }
953 :
954 : /****************************************************************************
955 : Return the filetype for UNIX extensions.
956 : ****************************************************************************/
957 :
958 0 : static uint32_t unix_filetype(mode_t mode)
959 : {
960 0 : if(S_ISREG(mode))
961 0 : return UNIX_TYPE_FILE;
962 0 : else if(S_ISDIR(mode))
963 0 : return UNIX_TYPE_DIR;
964 : #ifdef S_ISLNK
965 0 : else if(S_ISLNK(mode))
966 0 : return UNIX_TYPE_SYMLINK;
967 : #endif
968 : #ifdef S_ISCHR
969 0 : else if(S_ISCHR(mode))
970 0 : return UNIX_TYPE_CHARDEV;
971 : #endif
972 : #ifdef S_ISBLK
973 0 : else if(S_ISBLK(mode))
974 0 : return UNIX_TYPE_BLKDEV;
975 : #endif
976 : #ifdef S_ISFIFO
977 0 : else if(S_ISFIFO(mode))
978 0 : return UNIX_TYPE_FIFO;
979 : #endif
980 : #ifdef S_ISSOCK
981 0 : else if(S_ISSOCK(mode))
982 0 : return UNIX_TYPE_SOCKET;
983 : #endif
984 :
985 0 : DEBUG(0,("unix_filetype: unknown filetype %u\n", (unsigned)mode));
986 0 : return UNIX_TYPE_UNKNOWN;
987 : }
988 :
989 : /****************************************************************************
990 : Map wire perms onto standard UNIX permissions. Obey share restrictions.
991 : ****************************************************************************/
992 :
993 0 : NTSTATUS unix_perms_from_wire(connection_struct *conn,
994 : const SMB_STRUCT_STAT *psbuf,
995 : uint32_t perms,
996 : enum perm_type ptype,
997 : mode_t *ret_perms)
998 : {
999 0 : mode_t ret = 0;
1000 :
1001 0 : if (perms == SMB_MODE_NO_CHANGE) {
1002 0 : if (!VALID_STAT(*psbuf)) {
1003 0 : return NT_STATUS_INVALID_PARAMETER;
1004 : } else {
1005 0 : *ret_perms = psbuf->st_ex_mode;
1006 0 : return NT_STATUS_OK;
1007 : }
1008 : }
1009 :
1010 0 : ret = wire_perms_to_unix(perms);
1011 :
1012 0 : if (ptype == PERM_NEW_FILE) {
1013 : /*
1014 : * "create mask"/"force create mode" are
1015 : * only applied to new files, not existing ones.
1016 : */
1017 0 : ret &= lp_create_mask(SNUM(conn));
1018 : /* Add in force bits */
1019 0 : ret |= lp_force_create_mode(SNUM(conn));
1020 0 : } else if (ptype == PERM_NEW_DIR) {
1021 : /*
1022 : * "directory mask"/"force directory mode" are
1023 : * only applied to new directories, not existing ones.
1024 : */
1025 0 : ret &= lp_directory_mask(SNUM(conn));
1026 : /* Add in force bits */
1027 0 : ret |= lp_force_directory_mode(SNUM(conn));
1028 : }
1029 :
1030 0 : *ret_perms = ret;
1031 0 : return NT_STATUS_OK;
1032 : }
1033 :
1034 : /****************************************************************************
1035 : Needed to show the msdfs symlinks as directories. Modifies psbuf
1036 : to be a directory if it's a msdfs link.
1037 : ****************************************************************************/
1038 :
1039 76 : static bool check_msdfs_link(struct files_struct *dirfsp,
1040 : struct smb_filename *atname,
1041 : struct smb_filename *smb_fname)
1042 : {
1043 76 : int saved_errno = errno;
1044 152 : if(lp_host_msdfs() &&
1045 132 : lp_msdfs_root(SNUM(dirfsp->conn)) &&
1046 56 : is_msdfs_link(dirfsp, atname)) {
1047 :
1048 : /*
1049 : * Copy the returned stat struct from the relative
1050 : * to the full pathname.
1051 : */
1052 56 : smb_fname->st = atname->st;
1053 :
1054 56 : DEBUG(5,("check_msdfs_link: Masquerading msdfs link %s "
1055 : "as a directory\n",
1056 : smb_fname->base_name));
1057 56 : smb_fname->st.st_ex_mode =
1058 56 : (smb_fname->st.st_ex_mode & 0xFFF) | S_IFDIR;
1059 56 : errno = saved_errno;
1060 56 : return true;
1061 : }
1062 20 : errno = saved_errno;
1063 20 : return false;
1064 : }
1065 :
1066 :
1067 : /****************************************************************************
1068 : Get a level dependent lanman2 dir entry.
1069 : ****************************************************************************/
1070 :
1071 : struct smbd_dirptr_lanman2_state {
1072 : connection_struct *conn;
1073 : uint32_t info_level;
1074 : bool check_mangled_names;
1075 : bool has_wild;
1076 : bool got_exact_match;
1077 : bool case_sensitive;
1078 : };
1079 :
1080 11296 : static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx,
1081 : void *private_data,
1082 : const char *dname,
1083 : const char *mask,
1084 : char **_fname)
1085 : {
1086 11296 : struct smbd_dirptr_lanman2_state *state =
1087 : (struct smbd_dirptr_lanman2_state *)private_data;
1088 : bool ok;
1089 : char mangled_name[13]; /* mangled 8.3 name. */
1090 : bool got_match;
1091 : const char *fname;
1092 :
1093 : /* Mangle fname if it's an illegal name. */
1094 11296 : if (mangle_must_mangle(dname, state->conn->params)) {
1095 : /*
1096 : * Slow path - ensure we can push the original name as UCS2. If
1097 : * not, then just don't return this name.
1098 : */
1099 : NTSTATUS status;
1100 20 : size_t ret_len = 0;
1101 20 : size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1102 20 : uint8_t *tmp = talloc_array(talloc_tos(),
1103 : uint8_t,
1104 : len);
1105 :
1106 20 : status = srvstr_push(NULL,
1107 : FLAGS2_UNICODE_STRINGS,
1108 : tmp,
1109 : dname,
1110 : len,
1111 : STR_TERMINATE,
1112 : &ret_len);
1113 :
1114 20 : TALLOC_FREE(tmp);
1115 :
1116 20 : if (!NT_STATUS_IS_OK(status)) {
1117 12 : return false;
1118 : }
1119 :
1120 12 : ok = name_to_8_3(dname, mangled_name,
1121 12 : true, state->conn->params);
1122 12 : if (!ok) {
1123 0 : return false;
1124 : }
1125 12 : fname = mangled_name;
1126 : } else {
1127 11276 : fname = dname;
1128 : }
1129 :
1130 11288 : got_match = exact_match(state->has_wild,
1131 11288 : state->case_sensitive,
1132 : fname, mask);
1133 11288 : state->got_exact_match = got_match;
1134 11288 : if (!got_match) {
1135 11174 : got_match = mask_match(fname, mask,
1136 11174 : state->case_sensitive);
1137 : }
1138 :
1139 11770 : if(!got_match && state->check_mangled_names &&
1140 921 : !mangle_is_8_3(fname, false, state->conn->params)) {
1141 : /*
1142 : * It turns out that NT matches wildcards against
1143 : * both long *and* short names. This may explain some
1144 : * of the wildcard wierdness from old DOS clients
1145 : * that some people have been seeing.... JRA.
1146 : */
1147 : /* Force the mangling into 8.3. */
1148 539 : ok = name_to_8_3(fname, mangled_name,
1149 539 : false, state->conn->params);
1150 539 : if (!ok) {
1151 0 : return false;
1152 : }
1153 :
1154 539 : got_match = exact_match(state->has_wild,
1155 539 : state->case_sensitive,
1156 : mangled_name, mask);
1157 539 : state->got_exact_match = got_match;
1158 539 : if (!got_match) {
1159 539 : got_match = mask_match(mangled_name, mask,
1160 539 : state->case_sensitive);
1161 : }
1162 : }
1163 :
1164 11288 : if (!got_match) {
1165 921 : return false;
1166 : }
1167 :
1168 10367 : *_fname = talloc_strdup(ctx, fname);
1169 10367 : if (*_fname == NULL) {
1170 0 : return false;
1171 : }
1172 :
1173 10367 : return true;
1174 : }
1175 :
1176 10367 : static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
1177 : void *private_data,
1178 : struct files_struct *dirfsp,
1179 : struct smb_filename *atname,
1180 : struct smb_filename *smb_fname,
1181 : bool get_dosmode,
1182 : uint32_t *_mode)
1183 : {
1184 10367 : struct smbd_dirptr_lanman2_state *state =
1185 : (struct smbd_dirptr_lanman2_state *)private_data;
1186 10367 : bool ms_dfs_link = false;
1187 :
1188 10367 : if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
1189 0 : if (SMB_VFS_LSTAT(state->conn, smb_fname) != 0) {
1190 0 : DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1191 : "Couldn't lstat [%s] (%s)\n",
1192 : smb_fname_str_dbg(smb_fname),
1193 : strerror(errno)));
1194 0 : return false;
1195 : }
1196 0 : return true;
1197 : }
1198 :
1199 10443 : if (!VALID_STAT(smb_fname->st) &&
1200 76 : SMB_VFS_STAT(state->conn, smb_fname) != 0) {
1201 : /* Needed to show the msdfs symlinks as
1202 : * directories */
1203 :
1204 76 : ms_dfs_link = check_msdfs_link(dirfsp,
1205 : atname,
1206 : smb_fname);
1207 76 : if (!ms_dfs_link) {
1208 20 : DEBUG(5,("smbd_dirptr_lanman2_mode_fn: "
1209 : "Couldn't stat [%s] (%s)\n",
1210 : smb_fname_str_dbg(smb_fname),
1211 : strerror(errno)));
1212 20 : return false;
1213 : }
1214 :
1215 56 : *_mode = dos_mode_msdfs(state->conn, smb_fname);
1216 56 : return true;
1217 : }
1218 :
1219 10291 : if (!get_dosmode) {
1220 426 : return true;
1221 : }
1222 :
1223 9865 : *_mode = fdos_mode(smb_fname->fsp);
1224 9865 : smb_fname->st = smb_fname->fsp->fsp_name->st;
1225 :
1226 9865 : return true;
1227 : }
1228 :
1229 10343 : static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
1230 : connection_struct *conn,
1231 : uint16_t flags2,
1232 : uint32_t info_level,
1233 : struct ea_list *name_list,
1234 : bool check_mangled_names,
1235 : bool requires_resume_key,
1236 : uint32_t mode,
1237 : const char *fname,
1238 : const struct smb_filename *smb_fname,
1239 : int space_remaining,
1240 : uint8_t align,
1241 : bool do_pad,
1242 : char *base_data,
1243 : char **ppdata,
1244 : char *end_data,
1245 : uint64_t *last_entry_off)
1246 : {
1247 10343 : char *p, *q, *pdata = *ppdata;
1248 10343 : uint32_t reskey=0;
1249 10343 : uint64_t file_size = 0;
1250 10343 : uint64_t allocation_size = 0;
1251 10343 : uint64_t file_id = 0;
1252 10343 : size_t len = 0;
1253 10343 : struct timespec mdate_ts = {0};
1254 10343 : struct timespec adate_ts = {0};
1255 10343 : struct timespec cdate_ts = {0};
1256 10343 : struct timespec create_date_ts = {0};
1257 10343 : time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
1258 : char *nameptr;
1259 : char *last_entry_ptr;
1260 : bool was_8_3;
1261 : int off;
1262 10343 : int pad = 0;
1263 : NTSTATUS status;
1264 10343 : struct readdir_attr_data *readdir_attr_data = NULL;
1265 :
1266 10343 : if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) {
1267 918 : file_size = get_file_size_stat(&smb_fname->st);
1268 : }
1269 10343 : allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
1270 :
1271 : /*
1272 : * Skip SMB_VFS_FREADDIR_ATTR if the directory entry is a symlink or
1273 : * a DFS symlink.
1274 : */
1275 17348 : if (smb_fname->fsp != NULL &&
1276 9865 : !(mode & FILE_ATTRIBUTE_REPARSE_POINT)) {
1277 9865 : status = SMB_VFS_FREADDIR_ATTR(smb_fname->fsp,
1278 : ctx,
1279 : &readdir_attr_data);
1280 9865 : if (!NT_STATUS_IS_OK(status)) {
1281 9865 : if (!NT_STATUS_EQUAL(NT_STATUS_NOT_SUPPORTED,
1282 : status)) {
1283 0 : return status;
1284 : }
1285 : }
1286 : }
1287 :
1288 10343 : file_id = SMB_VFS_FS_FILE_ID(conn, &smb_fname->st);
1289 :
1290 10343 : mdate_ts = smb_fname->st.st_ex_mtime;
1291 10343 : adate_ts = smb_fname->st.st_ex_atime;
1292 10343 : create_date_ts = get_create_timespec(conn, NULL, smb_fname);
1293 10343 : cdate_ts = get_change_timespec(conn, NULL, smb_fname);
1294 :
1295 10343 : if (lp_dos_filetime_resolution(SNUM(conn))) {
1296 0 : dos_filetime_timespec(&create_date_ts);
1297 0 : dos_filetime_timespec(&mdate_ts);
1298 0 : dos_filetime_timespec(&adate_ts);
1299 0 : dos_filetime_timespec(&cdate_ts);
1300 : }
1301 :
1302 10343 : create_date = convert_timespec_to_time_t(create_date_ts);
1303 10343 : mdate = convert_timespec_to_time_t(mdate_ts);
1304 10343 : adate = convert_timespec_to_time_t(adate_ts);
1305 :
1306 : /* align the record */
1307 10343 : SMB_ASSERT(align >= 1);
1308 :
1309 10343 : off = (int)PTR_DIFF(pdata, base_data);
1310 10343 : pad = (off + (align-1)) & ~(align-1);
1311 10343 : pad -= off;
1312 :
1313 10343 : if (pad && pad > space_remaining) {
1314 0 : DEBUG(9,("smbd_marshall_dir_entry: out of space "
1315 : "for padding (wanted %u, had %d)\n",
1316 : (unsigned int)pad,
1317 : space_remaining ));
1318 0 : return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
1319 : }
1320 :
1321 10343 : off += pad;
1322 : /* initialize padding to 0 */
1323 10343 : if (pad) {
1324 7582 : memset(pdata, 0, pad);
1325 : }
1326 10343 : space_remaining -= pad;
1327 :
1328 10343 : DEBUG(10,("smbd_marshall_dir_entry: space_remaining = %d\n",
1329 : space_remaining ));
1330 :
1331 10343 : pdata += pad;
1332 10343 : p = pdata;
1333 10343 : last_entry_ptr = p;
1334 :
1335 10343 : pad = 0;
1336 10343 : off = 0;
1337 :
1338 10343 : switch (info_level) {
1339 0 : case SMB_FIND_INFO_STANDARD:
1340 0 : DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_INFO_STANDARD\n"));
1341 0 : if(requires_resume_key) {
1342 0 : SIVAL(p,0,reskey);
1343 0 : p += 4;
1344 : }
1345 0 : srv_put_dos_date2(p,0,create_date);
1346 0 : srv_put_dos_date2(p,4,adate);
1347 0 : srv_put_dos_date2(p,8,mdate);
1348 0 : SIVAL(p,12,(uint32_t)file_size);
1349 0 : SIVAL(p,16,(uint32_t)allocation_size);
1350 0 : SSVAL(p,20,mode);
1351 0 : p += 23;
1352 0 : nameptr = p;
1353 0 : if (flags2 & FLAGS2_UNICODE_STRINGS) {
1354 0 : p += ucs2_align(base_data, p, 0);
1355 : }
1356 0 : status = srvstr_push(base_data, flags2, p,
1357 : fname, PTR_DIFF(end_data, p),
1358 : STR_TERMINATE, &len);
1359 0 : if (!NT_STATUS_IS_OK(status)) {
1360 4 : return status;
1361 : }
1362 0 : if (flags2 & FLAGS2_UNICODE_STRINGS) {
1363 0 : if (len > 2) {
1364 0 : SCVAL(nameptr, -1, len - 2);
1365 : } else {
1366 0 : SCVAL(nameptr, -1, 0);
1367 : }
1368 : } else {
1369 0 : if (len > 1) {
1370 0 : SCVAL(nameptr, -1, len - 1);
1371 : } else {
1372 0 : SCVAL(nameptr, -1, 0);
1373 : }
1374 : }
1375 0 : p += len;
1376 0 : break;
1377 :
1378 0 : case SMB_FIND_EA_SIZE:
1379 0 : DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_SIZE\n"));
1380 0 : if (requires_resume_key) {
1381 0 : SIVAL(p,0,reskey);
1382 0 : p += 4;
1383 : }
1384 0 : srv_put_dos_date2(p,0,create_date);
1385 0 : srv_put_dos_date2(p,4,adate);
1386 0 : srv_put_dos_date2(p,8,mdate);
1387 0 : SIVAL(p,12,(uint32_t)file_size);
1388 0 : SIVAL(p,16,(uint32_t)allocation_size);
1389 0 : SSVAL(p,20,mode);
1390 : {
1391 0 : unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1392 0 : SIVAL(p,22,ea_size); /* Extended attributes */
1393 : }
1394 0 : p += 27;
1395 0 : nameptr = p - 1;
1396 0 : status = srvstr_push(base_data, flags2,
1397 : p, fname, PTR_DIFF(end_data, p),
1398 : STR_TERMINATE | STR_NOALIGN, &len);
1399 0 : if (!NT_STATUS_IS_OK(status)) {
1400 0 : return status;
1401 : }
1402 0 : if (flags2 & FLAGS2_UNICODE_STRINGS) {
1403 0 : if (len > 2) {
1404 0 : len -= 2;
1405 : } else {
1406 0 : len = 0;
1407 : }
1408 : } else {
1409 0 : if (len > 1) {
1410 0 : len -= 1;
1411 : } else {
1412 0 : len = 0;
1413 : }
1414 : }
1415 0 : SCVAL(nameptr,0,len);
1416 0 : p += len;
1417 0 : SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1418 0 : break;
1419 :
1420 0 : case SMB_FIND_EA_LIST:
1421 : {
1422 0 : struct ea_list *file_list = NULL;
1423 0 : size_t ea_len = 0;
1424 :
1425 0 : DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_LIST\n"));
1426 0 : if (!name_list) {
1427 0 : return NT_STATUS_INVALID_PARAMETER;
1428 : }
1429 0 : if (requires_resume_key) {
1430 0 : SIVAL(p,0,reskey);
1431 0 : p += 4;
1432 : }
1433 0 : srv_put_dos_date2(p,0,create_date);
1434 0 : srv_put_dos_date2(p,4,adate);
1435 0 : srv_put_dos_date2(p,8,mdate);
1436 0 : SIVAL(p,12,(uint32_t)file_size);
1437 0 : SIVAL(p,16,(uint32_t)allocation_size);
1438 0 : SSVAL(p,20,mode);
1439 0 : p += 22; /* p now points to the EA area. */
1440 :
1441 0 : status = get_ea_list_from_fsp(ctx,
1442 0 : smb_fname->fsp,
1443 : &ea_len, &file_list);
1444 0 : if (!NT_STATUS_IS_OK(status)) {
1445 0 : file_list = NULL;
1446 : }
1447 0 : name_list = ea_list_union(name_list, file_list, &ea_len);
1448 :
1449 : /* We need to determine if this entry will fit in the space available. */
1450 : /* Max string size is 255 bytes. */
1451 0 : if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
1452 0 : DEBUG(9,("smbd_marshall_dir_entry: out of space "
1453 : "(wanted %u, had %d)\n",
1454 : (unsigned int)PTR_DIFF(p + 255 + ea_len,pdata),
1455 : space_remaining ));
1456 0 : return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
1457 : }
1458 :
1459 : /* Push the ea_data followed by the name. */
1460 0 : p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
1461 0 : nameptr = p;
1462 0 : status = srvstr_push(base_data, flags2,
1463 : p + 1, fname, PTR_DIFF(end_data, p+1),
1464 : STR_TERMINATE | STR_NOALIGN, &len);
1465 0 : if (!NT_STATUS_IS_OK(status)) {
1466 0 : return status;
1467 : }
1468 0 : if (flags2 & FLAGS2_UNICODE_STRINGS) {
1469 0 : if (len > 2) {
1470 0 : len -= 2;
1471 : } else {
1472 0 : len = 0;
1473 : }
1474 : } else {
1475 0 : if (len > 1) {
1476 0 : len -= 1;
1477 : } else {
1478 0 : len = 0;
1479 : }
1480 : }
1481 0 : SCVAL(nameptr,0,len);
1482 0 : p += len + 1;
1483 0 : SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
1484 0 : break;
1485 : }
1486 :
1487 0 : case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
1488 0 : DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
1489 0 : was_8_3 = mangle_is_8_3(fname, True, conn->params);
1490 0 : p += 4;
1491 0 : SIVAL(p,0,reskey); p += 4;
1492 0 : put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1493 0 : put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1494 0 : put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1495 0 : put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1496 0 : SOFF_T(p,0,file_size); p += 8;
1497 0 : SOFF_T(p,0,allocation_size); p += 8;
1498 0 : SIVAL(p,0,mode); p += 4;
1499 0 : q = p; p += 4; /* q is placeholder for name length. */
1500 0 : if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1501 0 : SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1502 : } else {
1503 0 : unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1504 0 : SIVAL(p,0,ea_size); /* Extended attributes */
1505 : }
1506 0 : p += 4;
1507 : /* Clear the short name buffer. This is
1508 : * IMPORTANT as not doing so will trigger
1509 : * a Win2k client bug. JRA.
1510 : */
1511 0 : if (!was_8_3 && check_mangled_names) {
1512 : char mangled_name[13]; /* mangled 8.3 name. */
1513 0 : if (!name_to_8_3(fname,mangled_name,True,
1514 0 : conn->params)) {
1515 : /* Error - mangle failed ! */
1516 0 : memset(mangled_name,'\0',12);
1517 : }
1518 0 : mangled_name[12] = 0;
1519 0 : status = srvstr_push(base_data, flags2,
1520 : p+2, mangled_name, 24,
1521 : STR_UPPER|STR_UNICODE, &len);
1522 0 : if (!NT_STATUS_IS_OK(status)) {
1523 0 : return status;
1524 : }
1525 0 : if (len < 24) {
1526 0 : memset(p + 2 + len,'\0',24 - len);
1527 : }
1528 0 : SSVAL(p, 0, len);
1529 : } else {
1530 0 : memset(p,'\0',26);
1531 : }
1532 0 : p += 2 + 24;
1533 0 : status = srvstr_push(base_data, flags2, p,
1534 : fname, PTR_DIFF(end_data, p),
1535 : STR_TERMINATE_ASCII, &len);
1536 0 : if (!NT_STATUS_IS_OK(status)) {
1537 0 : return status;
1538 : }
1539 0 : SIVAL(q,0,len);
1540 0 : p += len;
1541 :
1542 0 : len = PTR_DIFF(p, pdata);
1543 0 : pad = (len + (align-1)) & ~(align-1);
1544 : /*
1545 : * offset to the next entry, the caller
1546 : * will overwrite it for the last entry
1547 : * that's why we always include the padding
1548 : */
1549 0 : SIVAL(pdata,0,pad);
1550 : /*
1551 : * set padding to zero
1552 : */
1553 0 : if (do_pad) {
1554 0 : memset(p, 0, pad - len);
1555 0 : p = pdata + pad;
1556 : } else {
1557 0 : p = pdata + len;
1558 : }
1559 0 : break;
1560 :
1561 0 : case SMB_FIND_FILE_DIRECTORY_INFO:
1562 0 : DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
1563 0 : p += 4;
1564 0 : SIVAL(p,0,reskey); p += 4;
1565 0 : put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1566 0 : put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1567 0 : put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1568 0 : put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1569 0 : SOFF_T(p,0,file_size); p += 8;
1570 0 : SOFF_T(p,0,allocation_size); p += 8;
1571 0 : SIVAL(p,0,mode); p += 4;
1572 0 : status = srvstr_push(base_data, flags2,
1573 : p + 4, fname, PTR_DIFF(end_data, p+4),
1574 : STR_TERMINATE_ASCII, &len);
1575 0 : if (!NT_STATUS_IS_OK(status)) {
1576 0 : return status;
1577 : }
1578 0 : SIVAL(p,0,len);
1579 0 : p += 4 + len;
1580 :
1581 0 : len = PTR_DIFF(p, pdata);
1582 0 : pad = (len + (align-1)) & ~(align-1);
1583 : /*
1584 : * offset to the next entry, the caller
1585 : * will overwrite it for the last entry
1586 : * that's why we always include the padding
1587 : */
1588 0 : SIVAL(pdata,0,pad);
1589 : /*
1590 : * set padding to zero
1591 : */
1592 0 : if (do_pad) {
1593 0 : memset(p, 0, pad - len);
1594 0 : p = pdata + pad;
1595 : } else {
1596 0 : p = pdata + len;
1597 : }
1598 0 : break;
1599 :
1600 0 : case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
1601 0 : DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
1602 0 : p += 4;
1603 0 : SIVAL(p,0,reskey); p += 4;
1604 0 : put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1605 0 : put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1606 0 : put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1607 0 : put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1608 0 : SOFF_T(p,0,file_size); p += 8;
1609 0 : SOFF_T(p,0,allocation_size); p += 8;
1610 0 : SIVAL(p,0,mode); p += 4;
1611 0 : q = p; p += 4; /* q is placeholder for name length. */
1612 0 : if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1613 0 : SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1614 : } else {
1615 0 : unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1616 0 : SIVAL(p,0,ea_size); /* Extended attributes */
1617 : }
1618 0 : p +=4;
1619 0 : status = srvstr_push(base_data, flags2, p,
1620 : fname, PTR_DIFF(end_data, p),
1621 : STR_TERMINATE_ASCII, &len);
1622 0 : if (!NT_STATUS_IS_OK(status)) {
1623 0 : return status;
1624 : }
1625 0 : SIVAL(q, 0, len);
1626 0 : p += len;
1627 :
1628 0 : len = PTR_DIFF(p, pdata);
1629 0 : pad = (len + (align-1)) & ~(align-1);
1630 : /*
1631 : * offset to the next entry, the caller
1632 : * will overwrite it for the last entry
1633 : * that's why we always include the padding
1634 : */
1635 0 : SIVAL(pdata,0,pad);
1636 : /*
1637 : * set padding to zero
1638 : */
1639 0 : if (do_pad) {
1640 0 : memset(p, 0, pad - len);
1641 0 : p = pdata + pad;
1642 : } else {
1643 0 : p = pdata + len;
1644 : }
1645 0 : break;
1646 :
1647 17 : case SMB_FIND_FILE_NAMES_INFO:
1648 17 : DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
1649 17 : p += 4;
1650 17 : SIVAL(p,0,reskey); p += 4;
1651 17 : p += 4;
1652 : /* this must *not* be null terminated or w2k gets in a loop trying to set an
1653 : acl on a dir (tridge) */
1654 17 : status = srvstr_push(base_data, flags2, p,
1655 : fname, PTR_DIFF(end_data, p),
1656 : STR_TERMINATE_ASCII, &len);
1657 17 : if (!NT_STATUS_IS_OK(status)) {
1658 0 : return status;
1659 : }
1660 17 : SIVAL(p, -4, len);
1661 17 : p += len;
1662 :
1663 17 : len = PTR_DIFF(p, pdata);
1664 17 : pad = (len + (align-1)) & ~(align-1);
1665 : /*
1666 : * offset to the next entry, the caller
1667 : * will overwrite it for the last entry
1668 : * that's why we always include the padding
1669 : */
1670 17 : SIVAL(pdata,0,pad);
1671 : /*
1672 : * set padding to zero
1673 : */
1674 17 : if (do_pad) {
1675 0 : memset(p, 0, pad - len);
1676 0 : p = pdata + pad;
1677 : } else {
1678 17 : p = pdata + len;
1679 : }
1680 17 : break;
1681 :
1682 0 : case SMB_FIND_ID_FULL_DIRECTORY_INFO:
1683 0 : DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
1684 0 : p += 4;
1685 0 : SIVAL(p,0,reskey); p += 4;
1686 0 : put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1687 0 : put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1688 0 : put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1689 0 : put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1690 0 : SOFF_T(p,0,file_size); p += 8;
1691 0 : SOFF_T(p,0,allocation_size); p += 8;
1692 0 : SIVAL(p,0,mode); p += 4;
1693 0 : q = p; p += 4; /* q is placeholder for name length. */
1694 0 : if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1695 0 : SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1696 : } else {
1697 0 : unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1698 0 : SIVAL(p,0,ea_size); /* Extended attributes */
1699 : }
1700 0 : p += 4;
1701 0 : SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
1702 0 : SBVAL(p,0,file_id); p += 8;
1703 0 : status = srvstr_push(base_data, flags2, p,
1704 : fname, PTR_DIFF(end_data, p),
1705 : STR_TERMINATE_ASCII, &len);
1706 0 : if (!NT_STATUS_IS_OK(status)) {
1707 0 : return status;
1708 : }
1709 0 : SIVAL(q, 0, len);
1710 0 : p += len;
1711 :
1712 0 : len = PTR_DIFF(p, pdata);
1713 0 : pad = (len + (align-1)) & ~(align-1);
1714 : /*
1715 : * offset to the next entry, the caller
1716 : * will overwrite it for the last entry
1717 : * that's why we always include the padding
1718 : */
1719 0 : SIVAL(pdata,0,pad);
1720 : /*
1721 : * set padding to zero
1722 : */
1723 0 : if (do_pad) {
1724 0 : memset(p, 0, pad - len);
1725 0 : p = pdata + pad;
1726 : } else {
1727 0 : p = pdata + len;
1728 : }
1729 0 : break;
1730 :
1731 10326 : case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
1732 10326 : DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
1733 10326 : was_8_3 = mangle_is_8_3(fname, True, conn->params);
1734 10326 : p += 4;
1735 10326 : SIVAL(p,0,reskey); p += 4;
1736 10326 : put_long_date_full_timespec(conn->ts_res,p,&create_date_ts); p += 8;
1737 10326 : put_long_date_full_timespec(conn->ts_res,p,&adate_ts); p += 8;
1738 10326 : put_long_date_full_timespec(conn->ts_res,p,&mdate_ts); p += 8;
1739 10326 : put_long_date_full_timespec(conn->ts_res,p,&cdate_ts); p += 8;
1740 10326 : SOFF_T(p,0,file_size); p += 8;
1741 10326 : SOFF_T(p,0,allocation_size); p += 8;
1742 10326 : SIVAL(p,0,mode); p += 4;
1743 10326 : q = p; p += 4; /* q is placeholder for name length */
1744 10326 : if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1745 56 : SIVAL(p, 0, IO_REPARSE_TAG_DFS);
1746 10270 : } else if (readdir_attr_data &&
1747 0 : readdir_attr_data->type == RDATTR_AAPL) {
1748 : /*
1749 : * OS X specific SMB2 extension negotiated via
1750 : * AAPL create context: return max_access in
1751 : * ea_size field.
1752 : */
1753 0 : SIVAL(p, 0, readdir_attr_data->attr_data.aapl.max_access);
1754 : } else {
1755 10270 : unsigned int ea_size = estimate_ea_size(smb_fname->fsp);
1756 10270 : SIVAL(p,0,ea_size); /* Extended attributes */
1757 : }
1758 10326 : p += 4;
1759 :
1760 10326 : if (readdir_attr_data &&
1761 0 : readdir_attr_data->type == RDATTR_AAPL) {
1762 : /*
1763 : * OS X specific SMB2 extension negotiated via
1764 : * AAPL create context: return resource fork
1765 : * length and compressed FinderInfo in
1766 : * shortname field.
1767 : *
1768 : * According to documentation short_name_len
1769 : * should be 0, but on the wire behaviour
1770 : * shows its set to 24 by clients.
1771 : */
1772 0 : SSVAL(p, 0, 24);
1773 :
1774 : /* Resourefork length */
1775 0 : SBVAL(p, 2, readdir_attr_data->attr_data.aapl.rfork_size);
1776 :
1777 : /* Compressed FinderInfo */
1778 0 : memcpy(p + 10, &readdir_attr_data->attr_data.aapl.finder_info, 16);
1779 11570 : } else if (!was_8_3 && check_mangled_names) {
1780 : char mangled_name[13]; /* mangled 8.3 name. */
1781 2238 : if (!name_to_8_3(fname,mangled_name,True,
1782 2238 : conn->params)) {
1783 : /* Error - mangle failed ! */
1784 0 : memset(mangled_name,'\0',12);
1785 : }
1786 2238 : mangled_name[12] = 0;
1787 2238 : status = srvstr_push(base_data, flags2,
1788 : p+2, mangled_name, 24,
1789 : STR_UPPER|STR_UNICODE, &len);
1790 2238 : if (!NT_STATUS_IS_OK(status)) {
1791 0 : return status;
1792 : }
1793 2238 : SSVAL(p, 0, len);
1794 2238 : if (len < 24) {
1795 2177 : memset(p + 2 + len,'\0',24 - len);
1796 : }
1797 2238 : SSVAL(p, 0, len);
1798 : } else {
1799 : /* Clear the short name buffer. This is
1800 : * IMPORTANT as not doing so will trigger
1801 : * a Win2k client bug. JRA.
1802 : */
1803 8088 : memset(p,'\0',26);
1804 : }
1805 10326 : p += 26;
1806 :
1807 : /* Reserved ? */
1808 10326 : if (readdir_attr_data &&
1809 0 : readdir_attr_data->type == RDATTR_AAPL) {
1810 : /*
1811 : * OS X specific SMB2 extension negotiated via
1812 : * AAPL create context: return UNIX mode in
1813 : * reserved field.
1814 : */
1815 0 : uint16_t aapl_mode = (uint16_t)readdir_attr_data->attr_data.aapl.unix_mode;
1816 0 : SSVAL(p, 0, aapl_mode);
1817 : } else {
1818 10326 : SSVAL(p, 0, 0);
1819 : }
1820 10326 : p += 2;
1821 :
1822 10326 : SBVAL(p,0,file_id); p += 8;
1823 10326 : status = srvstr_push(base_data, flags2, p,
1824 : fname, PTR_DIFF(end_data, p),
1825 : STR_TERMINATE_ASCII, &len);
1826 10326 : if (!NT_STATUS_IS_OK(status)) {
1827 8 : return status;
1828 : }
1829 10318 : SIVAL(q,0,len);
1830 10318 : p += len;
1831 :
1832 10318 : len = PTR_DIFF(p, pdata);
1833 10318 : pad = (len + (align-1)) & ~(align-1);
1834 : /*
1835 : * offset to the next entry, the caller
1836 : * will overwrite it for the last entry
1837 : * that's why we always include the padding
1838 : */
1839 10318 : SIVAL(pdata,0,pad);
1840 : /*
1841 : * set padding to zero
1842 : */
1843 10318 : if (do_pad) {
1844 0 : memset(p, 0, pad - len);
1845 0 : p = pdata + pad;
1846 : } else {
1847 10318 : p = pdata + len;
1848 : }
1849 10318 : break;
1850 :
1851 : /* CIFS UNIX Extension. */
1852 :
1853 0 : case SMB_FIND_FILE_UNIX:
1854 : case SMB_FIND_FILE_UNIX_INFO2:
1855 0 : p+= 4;
1856 0 : SIVAL(p,0,reskey); p+= 4; /* Used for continuing search. */
1857 :
1858 : /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
1859 :
1860 0 : if (info_level == SMB_FIND_FILE_UNIX) {
1861 0 : DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX\n"));
1862 0 : p = store_file_unix_basic(conn, p,
1863 : NULL, &smb_fname->st);
1864 0 : status = srvstr_push(base_data, flags2, p,
1865 : fname, PTR_DIFF(end_data, p),
1866 : STR_TERMINATE, &len);
1867 0 : if (!NT_STATUS_IS_OK(status)) {
1868 0 : return status;
1869 : }
1870 : } else {
1871 0 : DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
1872 0 : p = store_file_unix_basic_info2(conn, p,
1873 : NULL, &smb_fname->st);
1874 0 : nameptr = p;
1875 0 : p += 4;
1876 0 : status = srvstr_push(base_data, flags2, p, fname,
1877 : PTR_DIFF(end_data, p), 0, &len);
1878 0 : if (!NT_STATUS_IS_OK(status)) {
1879 0 : return status;
1880 : }
1881 0 : SIVAL(nameptr, 0, len);
1882 : }
1883 :
1884 0 : p += len;
1885 :
1886 0 : len = PTR_DIFF(p, pdata);
1887 0 : pad = (len + (align-1)) & ~(align-1);
1888 : /*
1889 : * offset to the next entry, the caller
1890 : * will overwrite it for the last entry
1891 : * that's why we always include the padding
1892 : */
1893 0 : SIVAL(pdata,0,pad);
1894 : /*
1895 : * set padding to zero
1896 : */
1897 0 : if (do_pad) {
1898 0 : memset(p, 0, pad - len);
1899 0 : p = pdata + pad;
1900 : } else {
1901 0 : p = pdata + len;
1902 : }
1903 : /* End of SMB_QUERY_FILE_UNIX_BASIC */
1904 :
1905 0 : break;
1906 :
1907 0 : default:
1908 0 : return NT_STATUS_INVALID_LEVEL;
1909 : }
1910 :
1911 10335 : if (PTR_DIFF(p,pdata) > space_remaining) {
1912 0 : DEBUG(9,("smbd_marshall_dir_entry: out of space "
1913 : "(wanted %u, had %d)\n",
1914 : (unsigned int)PTR_DIFF(p,pdata),
1915 : space_remaining ));
1916 0 : return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
1917 : }
1918 :
1919 : /* Setup the last entry pointer, as an offset from base_data */
1920 10335 : *last_entry_off = PTR_DIFF(last_entry_ptr,base_data);
1921 : /* Advance the data pointer to the next slot */
1922 10335 : *ppdata = p;
1923 :
1924 10335 : return NT_STATUS_OK;
1925 : }
1926 :
1927 14630 : NTSTATUS smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
1928 : connection_struct *conn,
1929 : struct dptr_struct *dirptr,
1930 : uint16_t flags2,
1931 : const char *path_mask,
1932 : uint32_t dirtype,
1933 : int info_level,
1934 : int requires_resume_key,
1935 : bool dont_descend,
1936 : bool ask_sharemode,
1937 : bool get_dosmode,
1938 : uint8_t align,
1939 : bool do_pad,
1940 : char **ppdata,
1941 : char *base_data,
1942 : char *end_data,
1943 : int space_remaining,
1944 : struct smb_filename **_smb_fname,
1945 : bool *got_exact_match,
1946 : int *_last_entry_off,
1947 : struct ea_list *name_list,
1948 : struct file_id *file_id)
1949 : {
1950 : const char *p;
1951 14630 : const char *mask = NULL;
1952 14630 : long prev_dirpos = 0;
1953 14630 : uint32_t mode = 0;
1954 14630 : char *fname = NULL;
1955 14630 : struct smb_filename *smb_fname = NULL;
1956 : struct smbd_dirptr_lanman2_state state;
1957 : bool ok;
1958 14630 : uint64_t last_entry_off = 0;
1959 : NTSTATUS status;
1960 : enum mangled_names_options mangled_names;
1961 : bool marshall_with_83_names;
1962 :
1963 14630 : mangled_names = lp_mangled_names(conn->params);
1964 :
1965 14630 : ZERO_STRUCT(state);
1966 14630 : state.conn = conn;
1967 14630 : state.info_level = info_level;
1968 14630 : if (mangled_names != MANGLED_NAMES_NO) {
1969 14630 : state.check_mangled_names = true;
1970 : }
1971 14630 : state.has_wild = dptr_has_wild(dirptr);
1972 14630 : state.got_exact_match = false;
1973 14630 : state.case_sensitive = dptr_case_sensitive(dirptr);
1974 :
1975 14630 : *got_exact_match = false;
1976 :
1977 14630 : p = strrchr_m(path_mask,'/');
1978 14630 : if(p != NULL) {
1979 0 : if(p[1] == '\0') {
1980 0 : mask = "*.*";
1981 : } else {
1982 0 : mask = p+1;
1983 : }
1984 : } else {
1985 14630 : mask = path_mask;
1986 : }
1987 :
1988 14630 : ok = smbd_dirptr_get_entry(ctx,
1989 : dirptr,
1990 : mask,
1991 : dirtype,
1992 : dont_descend,
1993 : ask_sharemode,
1994 : get_dosmode,
1995 : smbd_dirptr_lanman2_match_fn,
1996 : smbd_dirptr_lanman2_mode_fn,
1997 : &state,
1998 : &fname,
1999 : &smb_fname,
2000 : &mode,
2001 : &prev_dirpos);
2002 14630 : if (!ok) {
2003 4287 : return NT_STATUS_END_OF_FILE;
2004 : }
2005 :
2006 10343 : *got_exact_match = state.got_exact_match;
2007 :
2008 10343 : marshall_with_83_names = (mangled_names == MANGLED_NAMES_YES);
2009 :
2010 10343 : status = smbd_marshall_dir_entry(ctx,
2011 : conn,
2012 : flags2,
2013 : info_level,
2014 : name_list,
2015 : marshall_with_83_names,
2016 : requires_resume_key,
2017 : mode,
2018 : fname,
2019 : smb_fname,
2020 : space_remaining,
2021 : align,
2022 : do_pad,
2023 : base_data,
2024 : ppdata,
2025 : end_data,
2026 : &last_entry_off);
2027 10343 : if (NT_STATUS_EQUAL(status, NT_STATUS_ILLEGAL_CHARACTER)) {
2028 8 : DEBUG(1,("Conversion error: illegal character: %s\n",
2029 : smb_fname_str_dbg(smb_fname)));
2030 : }
2031 :
2032 10343 : if (file_id != NULL) {
2033 10343 : *file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
2034 : }
2035 :
2036 10347 : if (!NT_STATUS_IS_OK(status) &&
2037 8 : !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES))
2038 : {
2039 8 : TALLOC_FREE(smb_fname);
2040 8 : TALLOC_FREE(fname);
2041 8 : return status;
2042 : }
2043 :
2044 10335 : if (_smb_fname != NULL) {
2045 : /*
2046 : * smb_fname is already talloc'ed off ctx.
2047 : * We just need to make sure we don't return
2048 : * any stream_name, and replace base_name
2049 : * with fname in case base_name got mangled.
2050 : * This allows us to preserve any smb_fname->fsp
2051 : * for asynchronous handle lookups.
2052 : */
2053 10335 : TALLOC_FREE(smb_fname->stream_name);
2054 10335 : TALLOC_FREE(smb_fname->base_name);
2055 10335 : smb_fname->base_name = talloc_strdup(smb_fname, fname);
2056 :
2057 10335 : if (smb_fname->base_name == NULL) {
2058 0 : TALLOC_FREE(smb_fname);
2059 0 : TALLOC_FREE(fname);
2060 0 : return NT_STATUS_NO_MEMORY;
2061 : }
2062 10335 : *_smb_fname = smb_fname;
2063 : } else {
2064 0 : TALLOC_FREE(smb_fname);
2065 : }
2066 10335 : TALLOC_FREE(fname);
2067 :
2068 10335 : if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
2069 0 : dptr_SeekDir(dirptr, prev_dirpos);
2070 0 : return status;
2071 : }
2072 :
2073 10335 : *_last_entry_off = last_entry_off;
2074 10335 : return NT_STATUS_OK;
2075 : }
2076 :
2077 0 : unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16])
2078 : {
2079 0 : const struct loadparm_substitution *lp_sub =
2080 0 : loadparm_s3_global_substitution();
2081 :
2082 0 : E_md4hash(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),objid);
2083 0 : return objid;
2084 : }
2085 :
2086 0 : static void samba_extended_info_version(struct smb_extended_info *extended_info)
2087 : {
2088 0 : SMB_ASSERT(extended_info != NULL);
2089 :
2090 0 : extended_info->samba_magic = SAMBA_EXTENDED_INFO_MAGIC;
2091 0 : extended_info->samba_version = ((SAMBA_VERSION_MAJOR & 0xff) << 24)
2092 : | ((SAMBA_VERSION_MINOR & 0xff) << 16)
2093 : | ((SAMBA_VERSION_RELEASE & 0xff) << 8);
2094 : #ifdef SAMBA_VERSION_REVISION
2095 : extended_info->samba_version |= (tolower(*SAMBA_VERSION_REVISION) - 'a' + 1) & 0xff;
2096 : #endif
2097 0 : extended_info->samba_subversion = 0;
2098 : #ifdef SAMBA_VERSION_RC_RELEASE
2099 : extended_info->samba_subversion |= (SAMBA_VERSION_RC_RELEASE & 0xff) << 24;
2100 : #else
2101 : #ifdef SAMBA_VERSION_PRE_RELEASE
2102 : extended_info->samba_subversion |= (SAMBA_VERSION_PRE_RELEASE & 0xff) << 16;
2103 : #endif
2104 : #endif
2105 : #ifdef SAMBA_VERSION_VENDOR_PATCH
2106 : extended_info->samba_subversion |= (SAMBA_VERSION_VENDOR_PATCH & 0xffff);
2107 : #endif
2108 0 : extended_info->samba_gitcommitdate = 0;
2109 : #ifdef SAMBA_VERSION_COMMIT_TIME
2110 : unix_to_nt_time(&extended_info->samba_gitcommitdate, SAMBA_VERSION_COMMIT_TIME);
2111 : #endif
2112 :
2113 0 : memset(extended_info->samba_version_string, 0,
2114 : sizeof(extended_info->samba_version_string));
2115 :
2116 0 : snprintf (extended_info->samba_version_string,
2117 : sizeof(extended_info->samba_version_string),
2118 : "%s", samba_version_string());
2119 0 : }
2120 :
2121 387 : NTSTATUS smbd_do_qfsinfo(struct smbXsrv_connection *xconn,
2122 : connection_struct *conn,
2123 : TALLOC_CTX *mem_ctx,
2124 : uint16_t info_level,
2125 : uint16_t flags2,
2126 : unsigned int max_data_bytes,
2127 : size_t *fixed_portion,
2128 : struct smb_filename *fname,
2129 : char **ppdata,
2130 : int *ret_data_len)
2131 : {
2132 208 : const struct loadparm_substitution *lp_sub =
2133 179 : loadparm_s3_global_substitution();
2134 : char *pdata, *end_data;
2135 387 : int data_len = 0;
2136 387 : size_t len = 0;
2137 387 : const char *vname = volume_label(talloc_tos(), SNUM(conn));
2138 387 : int snum = SNUM(conn);
2139 387 : const char *fstype = lp_fstype(SNUM(conn));
2140 387 : const char *filename = NULL;
2141 387 : const uint64_t bytes_per_sector = 512;
2142 387 : uint32_t additional_flags = 0;
2143 : struct smb_filename smb_fname;
2144 : SMB_STRUCT_STAT st;
2145 387 : NTSTATUS status = NT_STATUS_OK;
2146 : uint64_t df_ret;
2147 : uint32_t serial;
2148 :
2149 387 : if (fname == NULL || fname->base_name == NULL) {
2150 8 : filename = ".";
2151 : } else {
2152 379 : filename = fname->base_name;
2153 : }
2154 :
2155 387 : if (IS_IPC(conn)) {
2156 0 : if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
2157 0 : DEBUG(0,("smbd_do_qfsinfo: not an allowed "
2158 : "info level (0x%x) on IPC$.\n",
2159 : (unsigned int)info_level));
2160 0 : return NT_STATUS_ACCESS_DENIED;
2161 : }
2162 : }
2163 :
2164 387 : DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level));
2165 :
2166 387 : smb_fname = (struct smb_filename) {
2167 : .base_name = discard_const_p(char, filename),
2168 387 : .flags = fname ? fname->flags : 0,
2169 387 : .twrp = fname ? fname->twrp : 0,
2170 : };
2171 :
2172 387 : if(info_level != SMB_FS_QUOTA_INFORMATION
2173 387 : && SMB_VFS_STAT(conn, &smb_fname) != 0) {
2174 0 : DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
2175 0 : return map_nt_error_from_unix(errno);
2176 : }
2177 :
2178 387 : st = smb_fname.st;
2179 :
2180 387 : if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
2181 0 : return NT_STATUS_INVALID_PARAMETER;
2182 : }
2183 :
2184 387 : *ppdata = (char *)SMB_REALLOC(
2185 : *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2186 387 : if (*ppdata == NULL) {
2187 0 : return NT_STATUS_NO_MEMORY;
2188 : }
2189 :
2190 387 : pdata = *ppdata;
2191 387 : memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
2192 387 : end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
2193 :
2194 387 : *fixed_portion = 0;
2195 :
2196 387 : switch (info_level) {
2197 0 : case SMB_INFO_ALLOCATION:
2198 : {
2199 : uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
2200 0 : data_len = 18;
2201 0 : df_ret = get_dfree_info(conn, &smb_fname, &bsize,
2202 : &dfree, &dsize);
2203 0 : if (df_ret == (uint64_t)-1) {
2204 0 : return map_nt_error_from_unix(errno);
2205 : }
2206 :
2207 0 : block_size = lp_block_size(snum);
2208 0 : if (bsize < block_size) {
2209 0 : uint64_t factor = block_size/bsize;
2210 0 : bsize = block_size;
2211 0 : dsize /= factor;
2212 0 : dfree /= factor;
2213 : }
2214 0 : if (bsize > block_size) {
2215 0 : uint64_t factor = bsize/block_size;
2216 0 : bsize = block_size;
2217 0 : dsize *= factor;
2218 0 : dfree *= factor;
2219 : }
2220 0 : sectors_per_unit = bsize/bytes_per_sector;
2221 :
2222 0 : DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
2223 : cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
2224 : (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2225 :
2226 : /*
2227 : * For large drives, return max values and not modulo.
2228 : */
2229 0 : dsize = MIN(dsize, UINT32_MAX);
2230 0 : dfree = MIN(dfree, UINT32_MAX);
2231 :
2232 0 : SIVAL(pdata,l1_idFileSystem,st.st_ex_dev);
2233 0 : SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
2234 0 : SIVAL(pdata,l1_cUnit,dsize);
2235 0 : SIVAL(pdata,l1_cUnitAvail,dfree);
2236 0 : SSVAL(pdata,l1_cbSector,bytes_per_sector);
2237 0 : break;
2238 : }
2239 :
2240 0 : case SMB_INFO_VOLUME:
2241 : /* Return volume name */
2242 : /*
2243 : * Add volume serial number - hash of a combination of
2244 : * the called hostname and the service name.
2245 : */
2246 0 : serial = generate_volume_serial_number(lp_sub, snum);
2247 0 : SIVAL(pdata,0,serial);
2248 : /*
2249 : * Win2k3 and previous mess this up by sending a name length
2250 : * one byte short. I believe only older clients (OS/2 Win9x) use
2251 : * this call so try fixing this by adding a terminating null to
2252 : * the pushed string. The change here was adding the STR_TERMINATE. JRA.
2253 : */
2254 0 : status = srvstr_push(
2255 : pdata, flags2,
2256 : pdata+l2_vol_szVolLabel, vname,
2257 : PTR_DIFF(end_data, pdata+l2_vol_szVolLabel),
2258 : STR_NOALIGN|STR_TERMINATE, &len);
2259 0 : if (!NT_STATUS_IS_OK(status)) {
2260 0 : return status;
2261 : }
2262 0 : SCVAL(pdata,l2_vol_cch,len);
2263 0 : data_len = l2_vol_szVolLabel + len;
2264 0 : DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %u, "
2265 : "name = %s serial = 0x%04"PRIx32"\n",
2266 : (unsigned)convert_timespec_to_time_t(st.st_ex_ctime),
2267 : (unsigned)len, vname, serial));
2268 0 : break;
2269 :
2270 0 : case SMB_QUERY_FS_ATTRIBUTE_INFO:
2271 : case SMB_FS_ATTRIBUTE_INFORMATION:
2272 :
2273 0 : additional_flags = 0;
2274 : #if defined(HAVE_SYS_QUOTAS)
2275 0 : additional_flags |= FILE_VOLUME_QUOTAS;
2276 : #endif
2277 :
2278 0 : if(lp_nt_acl_support(SNUM(conn))) {
2279 0 : additional_flags |= FILE_PERSISTENT_ACLS;
2280 : }
2281 :
2282 : /* Capabilities are filled in at connection time through STATVFS call */
2283 0 : additional_flags |= conn->fs_capabilities;
2284 0 : additional_flags |= lp_parm_int(conn->params->service,
2285 : "share", "fake_fscaps",
2286 : 0);
2287 :
2288 0 : SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
2289 : FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
2290 : additional_flags); /* FS ATTRIBUTES */
2291 :
2292 0 : SIVAL(pdata,4,255); /* Max filename component length */
2293 : /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
2294 : and will think we can't do long filenames */
2295 0 : status = srvstr_push(pdata, flags2, pdata+12, fstype,
2296 : PTR_DIFF(end_data, pdata+12),
2297 : STR_UNICODE, &len);
2298 0 : if (!NT_STATUS_IS_OK(status)) {
2299 0 : return status;
2300 : }
2301 0 : SIVAL(pdata,8,len);
2302 0 : data_len = 12 + len;
2303 0 : if (max_data_bytes >= 16 && data_len > max_data_bytes) {
2304 : /* the client only requested a portion of the
2305 : file system name */
2306 0 : data_len = max_data_bytes;
2307 0 : status = STATUS_BUFFER_OVERFLOW;
2308 : }
2309 0 : *fixed_portion = 16;
2310 0 : break;
2311 :
2312 0 : case SMB_QUERY_FS_LABEL_INFO:
2313 : case SMB_FS_LABEL_INFORMATION:
2314 0 : status = srvstr_push(pdata, flags2, pdata+4, vname,
2315 : PTR_DIFF(end_data, pdata+4), 0, &len);
2316 0 : if (!NT_STATUS_IS_OK(status)) {
2317 0 : return status;
2318 : }
2319 0 : data_len = 4 + len;
2320 0 : SIVAL(pdata,0,len);
2321 0 : break;
2322 :
2323 4 : case SMB_QUERY_FS_VOLUME_INFO:
2324 : case SMB_FS_VOLUME_INFORMATION:
2325 4 : put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER,
2326 : pdata, &st.st_ex_btime);
2327 : /*
2328 : * Add volume serial number - hash of a combination of
2329 : * the called hostname and the service name.
2330 : */
2331 4 : serial = generate_volume_serial_number(lp_sub, snum);
2332 4 : SIVAL(pdata,8,serial);
2333 :
2334 : /* Max label len is 32 characters. */
2335 4 : status = srvstr_push(pdata, flags2, pdata+18, vname,
2336 : PTR_DIFF(end_data, pdata+18),
2337 : STR_UNICODE, &len);
2338 4 : if (!NT_STATUS_IS_OK(status)) {
2339 0 : return status;
2340 : }
2341 4 : SIVAL(pdata,12,len);
2342 4 : data_len = 18+len;
2343 :
2344 4 : DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO "
2345 : "namelen = %d, vol=%s serv=%s "
2346 : "serial=0x%04"PRIx32"\n",
2347 : (int)strlen(vname),vname,
2348 : lp_servicename(talloc_tos(), lp_sub, snum),
2349 : serial));
2350 4 : if (max_data_bytes >= 24 && data_len > max_data_bytes) {
2351 : /* the client only requested a portion of the
2352 : volume label */
2353 0 : data_len = max_data_bytes;
2354 0 : status = STATUS_BUFFER_OVERFLOW;
2355 : }
2356 4 : *fixed_portion = 24;
2357 4 : break;
2358 :
2359 375 : case SMB_QUERY_FS_SIZE_INFO:
2360 : case SMB_FS_SIZE_INFORMATION:
2361 : {
2362 : uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
2363 375 : data_len = 24;
2364 375 : df_ret = get_dfree_info(conn, &smb_fname, &bsize,
2365 : &dfree, &dsize);
2366 375 : if (df_ret == (uint64_t)-1) {
2367 0 : return map_nt_error_from_unix(errno);
2368 : }
2369 375 : block_size = lp_block_size(snum);
2370 375 : if (bsize < block_size) {
2371 375 : uint64_t factor = block_size/bsize;
2372 375 : bsize = block_size;
2373 375 : dsize /= factor;
2374 375 : dfree /= factor;
2375 : }
2376 375 : if (bsize > block_size) {
2377 0 : uint64_t factor = bsize/block_size;
2378 0 : bsize = block_size;
2379 0 : dsize *= factor;
2380 0 : dfree *= factor;
2381 : }
2382 375 : sectors_per_unit = bsize/bytes_per_sector;
2383 375 : DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
2384 : cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
2385 : (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2386 375 : SBIG_UINT(pdata,0,dsize);
2387 375 : SBIG_UINT(pdata,8,dfree);
2388 375 : SIVAL(pdata,16,sectors_per_unit);
2389 375 : SIVAL(pdata,20,bytes_per_sector);
2390 375 : *fixed_portion = 24;
2391 375 : break;
2392 : }
2393 :
2394 0 : case SMB_FS_FULL_SIZE_INFORMATION:
2395 : {
2396 : uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
2397 0 : data_len = 32;
2398 0 : df_ret = get_dfree_info(conn, &smb_fname, &bsize,
2399 : &dfree, &dsize);
2400 0 : if (df_ret == (uint64_t)-1) {
2401 0 : return map_nt_error_from_unix(errno);
2402 : }
2403 0 : block_size = lp_block_size(snum);
2404 0 : if (bsize < block_size) {
2405 0 : uint64_t factor = block_size/bsize;
2406 0 : bsize = block_size;
2407 0 : dsize /= factor;
2408 0 : dfree /= factor;
2409 : }
2410 0 : if (bsize > block_size) {
2411 0 : uint64_t factor = bsize/block_size;
2412 0 : bsize = block_size;
2413 0 : dsize *= factor;
2414 0 : dfree *= factor;
2415 : }
2416 0 : sectors_per_unit = bsize/bytes_per_sector;
2417 0 : DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
2418 : cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
2419 : (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
2420 0 : SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
2421 0 : SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
2422 0 : SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
2423 0 : SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
2424 0 : SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
2425 0 : *fixed_portion = 32;
2426 0 : break;
2427 : }
2428 :
2429 0 : case SMB_QUERY_FS_DEVICE_INFO:
2430 : case SMB_FS_DEVICE_INFORMATION:
2431 : {
2432 0 : uint32_t characteristics = FILE_DEVICE_IS_MOUNTED;
2433 :
2434 0 : if (!CAN_WRITE(conn)) {
2435 0 : characteristics |= FILE_READ_ONLY_DEVICE;
2436 : }
2437 0 : data_len = 8;
2438 0 : SIVAL(pdata,0,FILE_DEVICE_DISK); /* dev type */
2439 0 : SIVAL(pdata,4,characteristics);
2440 0 : *fixed_portion = 8;
2441 0 : break;
2442 : }
2443 :
2444 : #ifdef HAVE_SYS_QUOTAS
2445 0 : case SMB_FS_QUOTA_INFORMATION:
2446 : /*
2447 : * what we have to send --metze:
2448 : *
2449 : * Unknown1: 24 NULL bytes
2450 : * Soft Quota Treshold: 8 bytes seems like uint64_t or so
2451 : * Hard Quota Limit: 8 bytes seems like uint64_t or so
2452 : * Quota Flags: 2 byte :
2453 : * Unknown3: 6 NULL bytes
2454 : *
2455 : * 48 bytes total
2456 : *
2457 : * details for Quota Flags:
2458 : *
2459 : * 0x0020 Log Limit: log if the user exceeds his Hard Quota
2460 : * 0x0010 Log Warn: log if the user exceeds his Soft Quota
2461 : * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
2462 : * 0x0001 Enable Quotas: enable quota for this fs
2463 : *
2464 : */
2465 : {
2466 : /* we need to fake up a fsp here,
2467 : * because its not send in this call
2468 : */
2469 : files_struct fsp;
2470 : SMB_NTQUOTA_STRUCT quotas;
2471 :
2472 0 : ZERO_STRUCT(fsp);
2473 0 : ZERO_STRUCT(quotas);
2474 :
2475 0 : fsp.conn = conn;
2476 0 : fsp.fnum = FNUM_FIELD_INVALID;
2477 :
2478 : /* access check */
2479 0 : if (get_current_uid(conn) != 0) {
2480 0 : DEBUG(0,("get_user_quota: access_denied "
2481 : "service [%s] user [%s]\n",
2482 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
2483 : conn->session_info->unix_info->unix_name));
2484 0 : return NT_STATUS_ACCESS_DENIED;
2485 : }
2486 :
2487 0 : status = vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE,
2488 : NULL, "as);
2489 0 : if (!NT_STATUS_IS_OK(status)) {
2490 0 : DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2491 0 : return status;
2492 : }
2493 :
2494 0 : data_len = 48;
2495 :
2496 0 : DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",
2497 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2498 :
2499 : /* Unknown1 24 NULL bytes*/
2500 0 : SBIG_UINT(pdata,0,(uint64_t)0);
2501 0 : SBIG_UINT(pdata,8,(uint64_t)0);
2502 0 : SBIG_UINT(pdata,16,(uint64_t)0);
2503 :
2504 : /* Default Soft Quota 8 bytes */
2505 0 : SBIG_UINT(pdata,24,quotas.softlim);
2506 :
2507 : /* Default Hard Quota 8 bytes */
2508 0 : SBIG_UINT(pdata,32,quotas.hardlim);
2509 :
2510 : /* Quota flag 2 bytes */
2511 0 : SSVAL(pdata,40,quotas.qflags);
2512 :
2513 : /* Unknown3 6 NULL bytes */
2514 0 : SSVAL(pdata,42,0);
2515 0 : SIVAL(pdata,44,0);
2516 :
2517 0 : break;
2518 : }
2519 : #endif /* HAVE_SYS_QUOTAS */
2520 0 : case SMB_FS_OBJECTID_INFORMATION:
2521 : {
2522 : unsigned char objid[16];
2523 : struct smb_extended_info extended_info;
2524 0 : memcpy(pdata,create_volume_objectid(conn, objid),16);
2525 0 : samba_extended_info_version (&extended_info);
2526 0 : SIVAL(pdata,16,extended_info.samba_magic);
2527 0 : SIVAL(pdata,20,extended_info.samba_version);
2528 0 : SIVAL(pdata,24,extended_info.samba_subversion);
2529 0 : SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
2530 0 : memcpy(pdata+36,extended_info.samba_version_string,28);
2531 0 : data_len = 64;
2532 0 : break;
2533 : }
2534 :
2535 0 : case SMB_FS_SECTOR_SIZE_INFORMATION:
2536 : {
2537 0 : data_len = 28;
2538 : /*
2539 : * These values match a physical Windows Server 2012
2540 : * share backed by NTFS atop spinning rust.
2541 : */
2542 0 : DEBUG(5, ("SMB_FS_SECTOR_SIZE_INFORMATION:"));
2543 : /* logical_bytes_per_sector */
2544 0 : SIVAL(pdata, 0, bytes_per_sector);
2545 : /* phys_bytes_per_sector_atomic */
2546 0 : SIVAL(pdata, 4, bytes_per_sector);
2547 : /* phys_bytes_per_sector_perf */
2548 0 : SIVAL(pdata, 8, bytes_per_sector);
2549 : /* fs_effective_phys_bytes_per_sector_atomic */
2550 0 : SIVAL(pdata, 12, bytes_per_sector);
2551 : /* flags */
2552 0 : SIVAL(pdata, 16, SSINFO_FLAGS_ALIGNED_DEVICE
2553 : | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE);
2554 : /* byte_off_sector_align */
2555 0 : SIVAL(pdata, 20, 0);
2556 : /* byte_off_partition_align */
2557 0 : SIVAL(pdata, 24, 0);
2558 0 : *fixed_portion = 28;
2559 0 : break;
2560 : }
2561 :
2562 :
2563 : #if defined(WITH_SMB1SERVER)
2564 : /*
2565 : * Query the version and capabilities of the CIFS UNIX extensions
2566 : * in use.
2567 : */
2568 :
2569 0 : case SMB_QUERY_CIFS_UNIX_INFO:
2570 : {
2571 0 : bool large_write = lp_min_receive_file_size() &&
2572 0 : !smb1_srv_is_signing_active(xconn);
2573 0 : bool large_read = !smb1_srv_is_signing_active(xconn);
2574 0 : int encrypt_caps = 0;
2575 :
2576 0 : if (!lp_smb1_unix_extensions()) {
2577 0 : return NT_STATUS_INVALID_LEVEL;
2578 : }
2579 :
2580 0 : switch (conn->encrypt_level) {
2581 0 : case SMB_SIGNING_OFF:
2582 0 : encrypt_caps = 0;
2583 0 : break;
2584 0 : case SMB_SIGNING_DESIRED:
2585 : case SMB_SIGNING_IF_REQUIRED:
2586 : case SMB_SIGNING_DEFAULT:
2587 0 : encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
2588 0 : break;
2589 0 : case SMB_SIGNING_REQUIRED:
2590 0 : encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP|
2591 : CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP;
2592 0 : large_write = false;
2593 0 : large_read = false;
2594 0 : break;
2595 : }
2596 :
2597 0 : data_len = 12;
2598 0 : SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
2599 0 : SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
2600 :
2601 : /* We have POSIX ACLs, pathname, encryption,
2602 : * large read/write, and locking capability. */
2603 :
2604 0 : SBIG_UINT(pdata,4,((uint64_t)(
2605 : CIFS_UNIX_POSIX_ACLS_CAP|
2606 : CIFS_UNIX_POSIX_PATHNAMES_CAP|
2607 : CIFS_UNIX_FCNTL_LOCKS_CAP|
2608 : CIFS_UNIX_EXTATTR_CAP|
2609 : CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP|
2610 : encrypt_caps|
2611 : (large_read ? CIFS_UNIX_LARGE_READ_CAP : 0) |
2612 : (large_write ?
2613 : CIFS_UNIX_LARGE_WRITE_CAP : 0))));
2614 0 : break;
2615 : }
2616 : #endif
2617 :
2618 0 : case SMB_QUERY_POSIX_FS_INFO:
2619 : {
2620 : int rc;
2621 : struct vfs_statvfs_struct svfs;
2622 :
2623 0 : if (!lp_smb1_unix_extensions()) {
2624 0 : return NT_STATUS_INVALID_LEVEL;
2625 : }
2626 :
2627 0 : rc = SMB_VFS_STATVFS(conn, &smb_fname, &svfs);
2628 :
2629 0 : if (!rc) {
2630 0 : data_len = 56;
2631 0 : SIVAL(pdata,0,svfs.OptimalTransferSize);
2632 0 : SIVAL(pdata,4,svfs.BlockSize);
2633 0 : SBIG_UINT(pdata,8,svfs.TotalBlocks);
2634 0 : SBIG_UINT(pdata,16,svfs.BlocksAvail);
2635 0 : SBIG_UINT(pdata,24,svfs.UserBlocksAvail);
2636 0 : SBIG_UINT(pdata,32,svfs.TotalFileNodes);
2637 0 : SBIG_UINT(pdata,40,svfs.FreeFileNodes);
2638 0 : SBIG_UINT(pdata,48,svfs.FsIdentifier);
2639 0 : DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
2640 : #ifdef EOPNOTSUPP
2641 0 : } else if (rc == EOPNOTSUPP) {
2642 0 : return NT_STATUS_INVALID_LEVEL;
2643 : #endif /* EOPNOTSUPP */
2644 : } else {
2645 0 : DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2646 0 : return NT_STATUS_DOS(ERRSRV, ERRerror);
2647 : }
2648 0 : break;
2649 : }
2650 :
2651 8 : case SMB_QUERY_POSIX_WHOAMI:
2652 : {
2653 8 : uint32_t flags = 0;
2654 : uint32_t sid_bytes;
2655 : uint32_t i;
2656 :
2657 8 : if (!lp_smb1_unix_extensions()) {
2658 0 : return NT_STATUS_INVALID_LEVEL;
2659 : }
2660 :
2661 8 : if (max_data_bytes < 40) {
2662 0 : return NT_STATUS_BUFFER_TOO_SMALL;
2663 : }
2664 :
2665 8 : if (security_session_user_level(conn->session_info, NULL) < SECURITY_USER) {
2666 0 : flags |= SMB_WHOAMI_GUEST;
2667 : }
2668 :
2669 : /* NOTE: 8 bytes for UID/GID, irrespective of native
2670 : * platform size. This matches
2671 : * SMB_QUERY_FILE_UNIX_BASIC and friends.
2672 : */
2673 8 : data_len = 4 /* flags */
2674 : + 4 /* flag mask */
2675 : + 8 /* uid */
2676 : + 8 /* gid */
2677 : + 4 /* ngroups */
2678 : + 4 /* num_sids */
2679 : + 4 /* SID bytes */
2680 : + 4 /* pad/reserved */
2681 8 : + (conn->session_info->unix_token->ngroups * 8)
2682 : /* groups list */
2683 8 : + (conn->session_info->security_token->num_sids *
2684 : SID_MAX_SIZE)
2685 : /* SID list */;
2686 :
2687 8 : SIVAL(pdata, 0, flags);
2688 8 : SIVAL(pdata, 4, SMB_WHOAMI_MASK);
2689 8 : SBIG_UINT(pdata, 8,
2690 : (uint64_t)conn->session_info->unix_token->uid);
2691 8 : SBIG_UINT(pdata, 16,
2692 : (uint64_t)conn->session_info->unix_token->gid);
2693 :
2694 :
2695 8 : if (data_len >= max_data_bytes) {
2696 : /* Potential overflow, skip the GIDs and SIDs. */
2697 :
2698 0 : SIVAL(pdata, 24, 0); /* num_groups */
2699 0 : SIVAL(pdata, 28, 0); /* num_sids */
2700 0 : SIVAL(pdata, 32, 0); /* num_sid_bytes */
2701 0 : SIVAL(pdata, 36, 0); /* reserved */
2702 :
2703 0 : data_len = 40;
2704 0 : break;
2705 : }
2706 :
2707 8 : SIVAL(pdata, 24, conn->session_info->unix_token->ngroups);
2708 8 : SIVAL(pdata, 28, conn->session_info->security_token->num_sids);
2709 :
2710 : /* We walk the SID list twice, but this call is fairly
2711 : * infrequent, and I don't expect that it's performance
2712 : * sensitive -- jpeach
2713 : */
2714 57 : for (i = 0, sid_bytes = 0;
2715 94 : i < conn->session_info->security_token->num_sids; ++i) {
2716 90 : sid_bytes += ndr_size_dom_sid(
2717 90 : &conn->session_info->security_token->sids[i],
2718 : 0);
2719 : }
2720 :
2721 : /* SID list byte count */
2722 8 : SIVAL(pdata, 32, sid_bytes);
2723 :
2724 : /* 4 bytes pad/reserved - must be zero */
2725 8 : SIVAL(pdata, 36, 0);
2726 8 : data_len = 40;
2727 :
2728 : /* GID list */
2729 44 : for (i = 0; i < conn->session_info->unix_token->ngroups; ++i) {
2730 36 : SBIG_UINT(pdata, data_len,
2731 : (uint64_t)conn->session_info->unix_token->groups[i]);
2732 36 : data_len += 8;
2733 : }
2734 :
2735 : /* SID list */
2736 57 : for (i = 0;
2737 94 : i < conn->session_info->security_token->num_sids; ++i) {
2738 135 : int sid_len = ndr_size_dom_sid(
2739 90 : &conn->session_info->security_token->sids[i],
2740 : 0);
2741 :
2742 90 : sid_linearize((uint8_t *)(pdata + data_len),
2743 : sid_len,
2744 90 : &conn->session_info->security_token->sids[i]);
2745 90 : data_len += sid_len;
2746 : }
2747 :
2748 8 : break;
2749 : }
2750 :
2751 0 : case SMB_MAC_QUERY_FS_INFO:
2752 : /*
2753 : * Thursby MAC extension... ONLY on NTFS filesystems
2754 : * once we do streams then we don't need this
2755 : */
2756 0 : if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
2757 0 : data_len = 88;
2758 0 : SIVAL(pdata,84,0x100); /* Don't support mac... */
2759 0 : break;
2760 : }
2761 :
2762 : FALL_THROUGH;
2763 : default:
2764 0 : return NT_STATUS_INVALID_LEVEL;
2765 : }
2766 :
2767 387 : *ret_data_len = data_len;
2768 387 : return status;
2769 : }
2770 :
2771 0 : NTSTATUS smb_set_fsquota(connection_struct *conn,
2772 : struct smb_request *req,
2773 : files_struct *fsp,
2774 : const DATA_BLOB *qdata)
2775 : {
2776 0 : const struct loadparm_substitution *lp_sub =
2777 0 : loadparm_s3_global_substitution();
2778 : NTSTATUS status;
2779 : SMB_NTQUOTA_STRUCT quotas;
2780 :
2781 0 : ZERO_STRUCT(quotas);
2782 :
2783 : /* access check */
2784 0 : if ((get_current_uid(conn) != 0) || !CAN_WRITE(conn)) {
2785 0 : DEBUG(3, ("set_fsquota: access_denied service [%s] user [%s]\n",
2786 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
2787 : conn->session_info->unix_info->unix_name));
2788 0 : return NT_STATUS_ACCESS_DENIED;
2789 : }
2790 :
2791 0 : if (!check_fsp_ntquota_handle(conn, req,
2792 : fsp)) {
2793 0 : DEBUG(1, ("set_fsquota: no valid QUOTA HANDLE\n"));
2794 0 : return NT_STATUS_INVALID_HANDLE;
2795 : }
2796 :
2797 : /* note: normally there're 48 bytes,
2798 : * but we didn't use the last 6 bytes for now
2799 : * --metze
2800 : */
2801 0 : if (qdata->length < 42) {
2802 0 : DEBUG(0,("set_fsquota: requires total_data(%u) >= 42 bytes!\n",
2803 : (unsigned int)qdata->length));
2804 0 : return NT_STATUS_INVALID_PARAMETER;
2805 : }
2806 :
2807 : /* unknown_1 24 NULL bytes in pdata*/
2808 :
2809 : /* the soft quotas 8 bytes (uint64_t)*/
2810 0 : quotas.softlim = BVAL(qdata->data,24);
2811 :
2812 : /* the hard quotas 8 bytes (uint64_t)*/
2813 0 : quotas.hardlim = BVAL(qdata->data,32);
2814 :
2815 : /* quota_flags 2 bytes **/
2816 0 : quotas.qflags = SVAL(qdata->data,40);
2817 :
2818 : /* unknown_2 6 NULL bytes follow*/
2819 :
2820 : /* now set the quotas */
2821 0 : if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, "as)!=0) {
2822 0 : DEBUG(1, ("vfs_set_ntquota() failed for service [%s]\n",
2823 : lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
2824 0 : status = map_nt_error_from_unix(errno);
2825 : } else {
2826 0 : status = NT_STATUS_OK;
2827 : }
2828 0 : return status;
2829 : }
2830 :
2831 0 : NTSTATUS smbd_do_setfsinfo(connection_struct *conn,
2832 : struct smb_request *req,
2833 : TALLOC_CTX *mem_ctx,
2834 : uint16_t info_level,
2835 : files_struct *fsp,
2836 : const DATA_BLOB *pdata)
2837 : {
2838 0 : switch (info_level) {
2839 0 : case SMB_FS_QUOTA_INFORMATION:
2840 : {
2841 0 : return smb_set_fsquota(conn,
2842 : req,
2843 : fsp,
2844 : pdata);
2845 : }
2846 :
2847 0 : default:
2848 0 : break;
2849 : }
2850 0 : return NT_STATUS_INVALID_LEVEL;
2851 : }
2852 :
2853 : #if defined(HAVE_POSIX_ACLS)
2854 : /****************************************************************************
2855 : Utility function to count the number of entries in a POSIX acl.
2856 : ****************************************************************************/
2857 :
2858 0 : static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
2859 : {
2860 0 : unsigned int ace_count = 0;
2861 0 : int entry_id = SMB_ACL_FIRST_ENTRY;
2862 : SMB_ACL_ENTRY_T entry;
2863 :
2864 0 : while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2865 : /* get_next... */
2866 0 : if (entry_id == SMB_ACL_FIRST_ENTRY) {
2867 0 : entry_id = SMB_ACL_NEXT_ENTRY;
2868 : }
2869 0 : ace_count++;
2870 : }
2871 0 : return ace_count;
2872 : }
2873 :
2874 : /****************************************************************************
2875 : Utility function to marshall a POSIX acl into wire format.
2876 : ****************************************************************************/
2877 :
2878 0 : static bool marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
2879 : {
2880 0 : int entry_id = SMB_ACL_FIRST_ENTRY;
2881 : SMB_ACL_ENTRY_T entry;
2882 :
2883 0 : while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
2884 : SMB_ACL_TAG_T tagtype;
2885 : SMB_ACL_PERMSET_T permset;
2886 0 : unsigned char perms = 0;
2887 : unsigned int own_grp;
2888 :
2889 : /* get_next... */
2890 0 : if (entry_id == SMB_ACL_FIRST_ENTRY) {
2891 0 : entry_id = SMB_ACL_NEXT_ENTRY;
2892 : }
2893 :
2894 0 : if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
2895 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
2896 0 : return False;
2897 : }
2898 :
2899 0 : if (sys_acl_get_permset(entry, &permset) == -1) {
2900 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
2901 0 : return False;
2902 : }
2903 :
2904 0 : perms |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
2905 0 : perms |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
2906 0 : perms |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
2907 :
2908 0 : SCVAL(pdata,1,perms);
2909 :
2910 0 : switch (tagtype) {
2911 0 : case SMB_ACL_USER_OBJ:
2912 0 : SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
2913 0 : own_grp = (unsigned int)pst->st_ex_uid;
2914 0 : SIVAL(pdata,2,own_grp);
2915 0 : SIVAL(pdata,6,0);
2916 0 : break;
2917 0 : case SMB_ACL_USER:
2918 : {
2919 0 : uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
2920 0 : if (!puid) {
2921 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2922 0 : return False;
2923 : }
2924 0 : own_grp = (unsigned int)*puid;
2925 0 : SCVAL(pdata,0,SMB_POSIX_ACL_USER);
2926 0 : SIVAL(pdata,2,own_grp);
2927 0 : SIVAL(pdata,6,0);
2928 0 : break;
2929 : }
2930 0 : case SMB_ACL_GROUP_OBJ:
2931 0 : SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
2932 0 : own_grp = (unsigned int)pst->st_ex_gid;
2933 0 : SIVAL(pdata,2,own_grp);
2934 0 : SIVAL(pdata,6,0);
2935 0 : break;
2936 0 : case SMB_ACL_GROUP:
2937 : {
2938 0 : gid_t *pgid= (gid_t *)sys_acl_get_qualifier(entry);
2939 0 : if (!pgid) {
2940 0 : DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
2941 0 : return False;
2942 : }
2943 0 : own_grp = (unsigned int)*pgid;
2944 0 : SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
2945 0 : SIVAL(pdata,2,own_grp);
2946 0 : SIVAL(pdata,6,0);
2947 0 : break;
2948 : }
2949 0 : case SMB_ACL_MASK:
2950 0 : SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
2951 0 : SIVAL(pdata,2,0xFFFFFFFF);
2952 0 : SIVAL(pdata,6,0xFFFFFFFF);
2953 0 : break;
2954 0 : case SMB_ACL_OTHER:
2955 0 : SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
2956 0 : SIVAL(pdata,2,0xFFFFFFFF);
2957 0 : SIVAL(pdata,6,0xFFFFFFFF);
2958 0 : break;
2959 0 : default:
2960 0 : DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
2961 0 : return False;
2962 : }
2963 0 : pdata += SMB_POSIX_ACL_ENTRY_SIZE;
2964 : }
2965 :
2966 0 : return True;
2967 : }
2968 : #endif
2969 :
2970 : /****************************************************************************
2971 : Store the FILE_UNIX_BASIC info.
2972 : ****************************************************************************/
2973 :
2974 0 : static char *store_file_unix_basic(connection_struct *conn,
2975 : char *pdata,
2976 : files_struct *fsp,
2977 : const SMB_STRUCT_STAT *psbuf)
2978 : {
2979 : dev_t devno;
2980 :
2981 0 : DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
2982 0 : DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode));
2983 :
2984 0 : SOFF_T(pdata,0,get_file_size_stat(psbuf)); /* File size 64 Bit */
2985 0 : pdata += 8;
2986 :
2987 0 : SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
2988 0 : pdata += 8;
2989 :
2990 0 : put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, &psbuf->st_ex_ctime); /* Change Time 64 Bit */
2991 0 : put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, &psbuf->st_ex_atime); /* Last access time 64 Bit */
2992 0 : put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, &psbuf->st_ex_mtime); /* Last modification time 64 Bit */
2993 0 : pdata += 24;
2994 :
2995 0 : SIVAL(pdata,0,psbuf->st_ex_uid); /* user id for the owner */
2996 0 : SIVAL(pdata,4,0);
2997 0 : pdata += 8;
2998 :
2999 0 : SIVAL(pdata,0,psbuf->st_ex_gid); /* group id of owner */
3000 0 : SIVAL(pdata,4,0);
3001 0 : pdata += 8;
3002 :
3003 0 : SIVAL(pdata,0,unix_filetype(psbuf->st_ex_mode));
3004 0 : pdata += 4;
3005 :
3006 0 : if (S_ISBLK(psbuf->st_ex_mode) || S_ISCHR(psbuf->st_ex_mode)) {
3007 0 : devno = psbuf->st_ex_rdev;
3008 : } else {
3009 0 : devno = psbuf->st_ex_dev;
3010 : }
3011 :
3012 0 : SIVAL(pdata,0,unix_dev_major(devno)); /* Major device number if type is device */
3013 0 : SIVAL(pdata,4,0);
3014 0 : pdata += 8;
3015 :
3016 0 : SIVAL(pdata,0,unix_dev_minor(devno)); /* Minor device number if type is device */
3017 0 : SIVAL(pdata,4,0);
3018 0 : pdata += 8;
3019 :
3020 0 : SINO_T_VAL(pdata, 0, psbuf->st_ex_ino); /* inode number */
3021 0 : pdata += 8;
3022 :
3023 0 : SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode)); /* Standard UNIX file permissions */
3024 0 : SIVAL(pdata,4,0);
3025 0 : pdata += 8;
3026 :
3027 0 : SIVAL(pdata,0,psbuf->st_ex_nlink); /* number of hard links */
3028 0 : SIVAL(pdata,4,0);
3029 0 : pdata += 8;
3030 :
3031 0 : return pdata;
3032 : }
3033 :
3034 : /* Forward and reverse mappings from the UNIX_INFO2 file flags field and
3035 : * the chflags(2) (or equivalent) flags.
3036 : *
3037 : * XXX: this really should be behind the VFS interface. To do this, we would
3038 : * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field.
3039 : * Each VFS module could then implement its own mapping as appropriate for the
3040 : * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS.
3041 : */
3042 : static const struct {unsigned stat_fflag; unsigned smb_fflag;}
3043 : info2_flags_map[] =
3044 : {
3045 : #ifdef UF_NODUMP
3046 : { UF_NODUMP, EXT_DO_NOT_BACKUP },
3047 : #endif
3048 :
3049 : #ifdef UF_IMMUTABLE
3050 : { UF_IMMUTABLE, EXT_IMMUTABLE },
3051 : #endif
3052 :
3053 : #ifdef UF_APPEND
3054 : { UF_APPEND, EXT_OPEN_APPEND_ONLY },
3055 : #endif
3056 :
3057 : #ifdef UF_HIDDEN
3058 : { UF_HIDDEN, EXT_HIDDEN },
3059 : #endif
3060 :
3061 : /* Do not remove. We need to guarantee that this array has at least one
3062 : * entry to build on HP-UX.
3063 : */
3064 : { 0, 0 }
3065 :
3066 : };
3067 :
3068 0 : static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
3069 : uint32_t *smb_fflags, uint32_t *smb_fmask)
3070 : {
3071 : size_t i;
3072 :
3073 0 : for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3074 0 : *smb_fmask |= info2_flags_map[i].smb_fflag;
3075 0 : if (psbuf->st_ex_flags & info2_flags_map[i].stat_fflag) {
3076 0 : *smb_fflags |= info2_flags_map[i].smb_fflag;
3077 : }
3078 : }
3079 0 : }
3080 :
3081 0 : static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
3082 : const uint32_t smb_fflags,
3083 : const uint32_t smb_fmask,
3084 : int *stat_fflags)
3085 : {
3086 0 : uint32_t max_fmask = 0;
3087 : size_t i;
3088 :
3089 0 : *stat_fflags = psbuf->st_ex_flags;
3090 :
3091 : /* For each flags requested in smb_fmask, check the state of the
3092 : * corresponding flag in smb_fflags and set or clear the matching
3093 : * stat flag.
3094 : */
3095 :
3096 0 : for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
3097 0 : max_fmask |= info2_flags_map[i].smb_fflag;
3098 0 : if (smb_fmask & info2_flags_map[i].smb_fflag) {
3099 0 : if (smb_fflags & info2_flags_map[i].smb_fflag) {
3100 0 : *stat_fflags |= info2_flags_map[i].stat_fflag;
3101 : } else {
3102 0 : *stat_fflags &= ~info2_flags_map[i].stat_fflag;
3103 : }
3104 : }
3105 : }
3106 :
3107 : /* If smb_fmask is asking to set any bits that are not supported by
3108 : * our flag mappings, we should fail.
3109 : */
3110 0 : if ((smb_fmask & max_fmask) != smb_fmask) {
3111 0 : return False;
3112 : }
3113 :
3114 0 : return True;
3115 : }
3116 :
3117 :
3118 : /* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition
3119 : * of file flags and birth (create) time.
3120 : */
3121 0 : static char *store_file_unix_basic_info2(connection_struct *conn,
3122 : char *pdata,
3123 : files_struct *fsp,
3124 : const SMB_STRUCT_STAT *psbuf)
3125 : {
3126 0 : uint32_t file_flags = 0;
3127 0 : uint32_t flags_mask = 0;
3128 :
3129 0 : pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
3130 :
3131 : /* Create (birth) time 64 bit */
3132 0 : put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, &psbuf->st_ex_btime);
3133 0 : pdata += 8;
3134 :
3135 0 : map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
3136 0 : SIVAL(pdata, 0, file_flags); /* flags */
3137 0 : SIVAL(pdata, 4, flags_mask); /* mask */
3138 0 : pdata += 8;
3139 :
3140 0 : return pdata;
3141 : }
3142 :
3143 44 : static NTSTATUS marshall_stream_info(unsigned int num_streams,
3144 : const struct stream_struct *streams,
3145 : char *data,
3146 : unsigned int max_data_bytes,
3147 : unsigned int *data_size)
3148 : {
3149 : unsigned int i;
3150 44 : unsigned int ofs = 0;
3151 :
3152 44 : if (max_data_bytes < 32) {
3153 0 : return NT_STATUS_INFO_LENGTH_MISMATCH;
3154 : }
3155 :
3156 120 : for (i = 0; i < num_streams; i++) {
3157 : unsigned int next_offset;
3158 : size_t namelen;
3159 : smb_ucs2_t *namebuf;
3160 :
3161 36 : if (!push_ucs2_talloc(talloc_tos(), &namebuf,
3162 54 : streams[i].name, &namelen) ||
3163 36 : namelen <= 2)
3164 : {
3165 0 : return NT_STATUS_INVALID_PARAMETER;
3166 : }
3167 :
3168 : /*
3169 : * name_buf is now null-terminated, we need to marshall as not
3170 : * terminated
3171 : */
3172 :
3173 36 : namelen -= 2;
3174 :
3175 : /*
3176 : * We cannot overflow ...
3177 : */
3178 36 : if ((ofs + 24 + namelen) > max_data_bytes) {
3179 0 : DEBUG(10, ("refusing to overflow reply at stream %u\n",
3180 : i));
3181 0 : TALLOC_FREE(namebuf);
3182 0 : return STATUS_BUFFER_OVERFLOW;
3183 : }
3184 :
3185 36 : SIVAL(data, ofs+4, namelen);
3186 36 : SOFF_T(data, ofs+8, streams[i].size);
3187 36 : SOFF_T(data, ofs+16, streams[i].alloc_size);
3188 36 : memcpy(data+ofs+24, namebuf, namelen);
3189 36 : TALLOC_FREE(namebuf);
3190 :
3191 36 : next_offset = ofs + 24 + namelen;
3192 :
3193 36 : if (i == num_streams-1) {
3194 36 : SIVAL(data, ofs, 0);
3195 : }
3196 : else {
3197 0 : unsigned int align = ndr_align_size(next_offset, 8);
3198 :
3199 0 : if ((next_offset + align) > max_data_bytes) {
3200 0 : DEBUG(10, ("refusing to overflow align "
3201 : "reply at stream %u\n",
3202 : i));
3203 0 : TALLOC_FREE(namebuf);
3204 0 : return STATUS_BUFFER_OVERFLOW;
3205 : }
3206 :
3207 0 : memset(data+next_offset, 0, align);
3208 0 : next_offset += align;
3209 :
3210 0 : SIVAL(data, ofs, next_offset - ofs);
3211 0 : ofs = next_offset;
3212 : }
3213 :
3214 36 : ofs = next_offset;
3215 : }
3216 :
3217 44 : DEBUG(10, ("max_data: %u, data_size: %u\n", max_data_bytes, ofs));
3218 :
3219 44 : *data_size = ofs;
3220 :
3221 44 : return NT_STATUS_OK;
3222 : }
3223 :
3224 0 : static NTSTATUS smb_unix_read_symlink(connection_struct *conn,
3225 : struct smb_request *req,
3226 : struct smb_filename *smb_fname,
3227 : char *pdata,
3228 : unsigned int data_size_in,
3229 : unsigned int *pdata_size_out)
3230 : {
3231 : NTSTATUS status;
3232 0 : size_t len = 0;
3233 0 : int link_len = 0;
3234 0 : struct smb_filename *parent_fname = NULL;
3235 0 : struct smb_filename *base_name = NULL;
3236 :
3237 0 : char *buffer = talloc_array(talloc_tos(), char, PATH_MAX+1);
3238 :
3239 0 : if (!buffer) {
3240 0 : return NT_STATUS_NO_MEMORY;
3241 : }
3242 :
3243 0 : DBG_DEBUG("SMB_QUERY_FILE_UNIX_LINK for file %s\n",
3244 : smb_fname_str_dbg(smb_fname));
3245 :
3246 0 : if(!S_ISLNK(smb_fname->st.st_ex_mode)) {
3247 0 : TALLOC_FREE(buffer);
3248 0 : return NT_STATUS_DOS(ERRSRV, ERRbadlink);
3249 : }
3250 :
3251 0 : status = parent_pathref(talloc_tos(),
3252 : conn->cwd_fsp,
3253 : smb_fname,
3254 : &parent_fname,
3255 : &base_name);
3256 0 : if (!NT_STATUS_IS_OK(status)) {
3257 0 : TALLOC_FREE(buffer);
3258 0 : return status;
3259 : }
3260 :
3261 0 : link_len = SMB_VFS_READLINKAT(conn,
3262 : parent_fname->fsp,
3263 : base_name,
3264 : buffer,
3265 : PATH_MAX);
3266 :
3267 0 : TALLOC_FREE(parent_fname);
3268 :
3269 0 : if (link_len == -1) {
3270 0 : TALLOC_FREE(buffer);
3271 0 : return map_nt_error_from_unix(errno);
3272 : }
3273 :
3274 0 : buffer[link_len] = 0;
3275 0 : status = srvstr_push(pdata,
3276 : req->flags2,
3277 : pdata,
3278 : buffer,
3279 : data_size_in,
3280 : STR_TERMINATE,
3281 : &len);
3282 0 : TALLOC_FREE(buffer);
3283 0 : if (!NT_STATUS_IS_OK(status)) {
3284 0 : return status;
3285 : }
3286 0 : *pdata_size_out = len;
3287 :
3288 0 : return NT_STATUS_OK;
3289 : }
3290 :
3291 : #if defined(HAVE_POSIX_ACLS)
3292 0 : static NTSTATUS smb_query_posix_acl(connection_struct *conn,
3293 : struct smb_request *req,
3294 : files_struct *fsp,
3295 : struct smb_filename *smb_fname,
3296 : char *pdata,
3297 : unsigned int data_size_in,
3298 : unsigned int *pdata_size_out)
3299 : {
3300 0 : SMB_ACL_T file_acl = NULL;
3301 0 : SMB_ACL_T def_acl = NULL;
3302 0 : uint16_t num_file_acls = 0;
3303 0 : uint16_t num_def_acls = 0;
3304 0 : unsigned int size_needed = 0;
3305 : NTSTATUS status;
3306 : bool ok;
3307 0 : bool close_fsp = false;
3308 :
3309 : /*
3310 : * Ensure we always operate on a file descriptor, not just
3311 : * the filename.
3312 : */
3313 0 : if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
3314 0 : uint32_t access_mask = SEC_STD_READ_CONTROL|
3315 : FILE_READ_ATTRIBUTES|
3316 : FILE_WRITE_ATTRIBUTES;
3317 :
3318 0 : status = get_posix_fsp(conn,
3319 : req,
3320 : smb_fname,
3321 : access_mask,
3322 : &fsp);
3323 :
3324 0 : if (!NT_STATUS_IS_OK(status)) {
3325 0 : goto out;
3326 : }
3327 0 : close_fsp = true;
3328 : }
3329 :
3330 0 : SMB_ASSERT(fsp != NULL);
3331 :
3332 0 : status = refuse_symlink_fsp(fsp);
3333 0 : if (!NT_STATUS_IS_OK(status)) {
3334 0 : goto out;
3335 : }
3336 :
3337 0 : file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, SMB_ACL_TYPE_ACCESS,
3338 : talloc_tos());
3339 :
3340 0 : if (file_acl == NULL && no_acl_syscall_error(errno)) {
3341 0 : DBG_INFO("ACLs not implemented on "
3342 : "filesystem containing %s\n",
3343 : fsp_str_dbg(fsp));
3344 0 : status = NT_STATUS_NOT_IMPLEMENTED;
3345 0 : goto out;
3346 : }
3347 :
3348 0 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
3349 : /*
3350 : * We can only have default POSIX ACLs on
3351 : * directories.
3352 : */
3353 0 : if (!fsp->fsp_flags.is_directory) {
3354 0 : DBG_INFO("Non-directory open %s\n",
3355 : fsp_str_dbg(fsp));
3356 0 : status = NT_STATUS_INVALID_HANDLE;
3357 0 : goto out;
3358 : }
3359 0 : def_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
3360 : SMB_ACL_TYPE_DEFAULT,
3361 : talloc_tos());
3362 0 : def_acl = free_empty_sys_acl(conn, def_acl);
3363 : }
3364 :
3365 0 : num_file_acls = count_acl_entries(conn, file_acl);
3366 0 : num_def_acls = count_acl_entries(conn, def_acl);
3367 :
3368 : /* Wrap checks. */
3369 0 : if (num_file_acls + num_def_acls < num_file_acls) {
3370 0 : status = NT_STATUS_INVALID_PARAMETER;
3371 0 : goto out;
3372 : }
3373 :
3374 0 : size_needed = num_file_acls + num_def_acls;
3375 :
3376 : /*
3377 : * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
3378 : * than UINT_MAX, so check by division.
3379 : */
3380 0 : if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
3381 0 : status = NT_STATUS_INVALID_PARAMETER;
3382 0 : goto out;
3383 : }
3384 :
3385 0 : size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
3386 0 : if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
3387 0 : status = NT_STATUS_INVALID_PARAMETER;
3388 0 : goto out;
3389 : }
3390 0 : size_needed += SMB_POSIX_ACL_HEADER_SIZE;
3391 :
3392 0 : if ( data_size_in < size_needed) {
3393 0 : DBG_INFO("data_size too small (%u) need %u\n",
3394 : data_size_in,
3395 : size_needed);
3396 0 : status = NT_STATUS_BUFFER_TOO_SMALL;
3397 0 : goto out;
3398 : }
3399 :
3400 0 : SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
3401 0 : SSVAL(pdata,2,num_file_acls);
3402 0 : SSVAL(pdata,4,num_def_acls);
3403 0 : pdata += SMB_POSIX_ACL_HEADER_SIZE;
3404 :
3405 0 : ok = marshall_posix_acl(conn,
3406 : pdata,
3407 0 : &fsp->fsp_name->st,
3408 : file_acl);
3409 0 : if (!ok) {
3410 0 : status = NT_STATUS_INTERNAL_ERROR;
3411 0 : goto out;
3412 : }
3413 0 : pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
3414 :
3415 0 : ok = marshall_posix_acl(conn,
3416 : pdata,
3417 0 : &fsp->fsp_name->st,
3418 : def_acl);
3419 0 : if (!ok) {
3420 0 : status = NT_STATUS_INTERNAL_ERROR;
3421 0 : goto out;
3422 : }
3423 :
3424 0 : *pdata_size_out = size_needed;
3425 0 : status = NT_STATUS_OK;
3426 :
3427 0 : out:
3428 :
3429 0 : if (close_fsp) {
3430 : /*
3431 : * Ensure the stat struct in smb_fname is up to
3432 : * date. Structure copy.
3433 : */
3434 0 : smb_fname->st = fsp->fsp_name->st;
3435 0 : (void)close_file_free(req, &fsp, NORMAL_CLOSE);
3436 : }
3437 :
3438 0 : TALLOC_FREE(file_acl);
3439 0 : TALLOC_FREE(def_acl);
3440 0 : return status;
3441 : }
3442 : #endif
3443 :
3444 910 : NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
3445 : TALLOC_CTX *mem_ctx,
3446 : struct smb_request *req,
3447 : uint16_t info_level,
3448 : files_struct *fsp,
3449 : struct smb_filename *smb_fname,
3450 : bool delete_pending,
3451 : struct timespec write_time_ts,
3452 : struct ea_list *ea_list,
3453 : int lock_data_count,
3454 : char *lock_data,
3455 : uint16_t flags2,
3456 : unsigned int max_data_bytes,
3457 : size_t *fixed_portion,
3458 : char **ppdata,
3459 : unsigned int *pdata_size)
3460 : {
3461 910 : char *pdata = *ppdata;
3462 : char *dstart, *dend;
3463 : unsigned int data_size;
3464 : struct timespec create_time_ts, mtime_ts, atime_ts, ctime_ts;
3465 : time_t create_time, mtime, atime, c_time;
3466 910 : SMB_STRUCT_STAT *psbuf = NULL;
3467 910 : SMB_STRUCT_STAT *base_sp = NULL;
3468 : char *p;
3469 : char *base_name;
3470 : char *dos_fname;
3471 : int mode;
3472 : int nlink;
3473 : NTSTATUS status;
3474 910 : uint64_t file_size = 0;
3475 910 : uint64_t pos = 0;
3476 910 : uint64_t allocation_size = 0;
3477 910 : uint64_t file_id = 0;
3478 910 : uint32_t access_mask = 0;
3479 910 : size_t len = 0;
3480 :
3481 910 : if (INFO_LEVEL_IS_UNIX(info_level)) {
3482 0 : if (!lp_smb1_unix_extensions()) {
3483 0 : return NT_STATUS_INVALID_LEVEL;
3484 : }
3485 0 : if (!req->posix_pathnames) {
3486 0 : return NT_STATUS_INVALID_LEVEL;
3487 : }
3488 : }
3489 :
3490 910 : DEBUG(5,("smbd_do_qfilepathinfo: %s (%s) level=%d max_data=%u\n",
3491 : smb_fname_str_dbg(smb_fname),
3492 : fsp_fnum_dbg(fsp),
3493 : info_level, max_data_bytes));
3494 :
3495 : /*
3496 : * In case of querying a symlink in POSIX context,
3497 : * fsp will be NULL. fdos_mode() deals with it.
3498 : */
3499 910 : if (fsp != NULL) {
3500 910 : smb_fname = fsp->fsp_name;
3501 : }
3502 910 : mode = fdos_mode(fsp);
3503 910 : psbuf = &smb_fname->st;
3504 :
3505 910 : if (fsp != NULL) {
3506 1559 : base_sp = fsp->base_fsp ?
3507 1547 : &fsp->base_fsp->fsp_name->st :
3508 886 : &fsp->fsp_name->st;
3509 : } else {
3510 0 : base_sp = &smb_fname->st;
3511 : }
3512 :
3513 910 : nlink = psbuf->st_ex_nlink;
3514 :
3515 910 : if (nlink && (mode&FILE_ATTRIBUTE_DIRECTORY)) {
3516 83 : nlink = 1;
3517 : }
3518 :
3519 910 : if ((nlink > 0) && delete_pending) {
3520 0 : nlink -= 1;
3521 : }
3522 :
3523 910 : if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
3524 0 : return NT_STATUS_INVALID_PARAMETER;
3525 : }
3526 :
3527 910 : data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
3528 910 : *ppdata = (char *)SMB_REALLOC(*ppdata, data_size);
3529 910 : if (*ppdata == NULL) {
3530 0 : return NT_STATUS_NO_MEMORY;
3531 : }
3532 910 : pdata = *ppdata;
3533 910 : dstart = pdata;
3534 910 : dend = dstart + data_size - 1;
3535 :
3536 910 : if (!is_omit_timespec(&write_time_ts) &&
3537 827 : !INFO_LEVEL_IS_UNIX(info_level))
3538 : {
3539 827 : update_stat_ex_mtime(psbuf, write_time_ts);
3540 : }
3541 :
3542 910 : create_time_ts = get_create_timespec(conn, fsp, smb_fname);
3543 910 : mtime_ts = psbuf->st_ex_mtime;
3544 910 : atime_ts = psbuf->st_ex_atime;
3545 910 : ctime_ts = get_change_timespec(conn, fsp, smb_fname);
3546 :
3547 910 : if (lp_dos_filetime_resolution(SNUM(conn))) {
3548 0 : dos_filetime_timespec(&create_time_ts);
3549 0 : dos_filetime_timespec(&mtime_ts);
3550 0 : dos_filetime_timespec(&atime_ts);
3551 0 : dos_filetime_timespec(&ctime_ts);
3552 : }
3553 :
3554 910 : create_time = convert_timespec_to_time_t(create_time_ts);
3555 910 : mtime = convert_timespec_to_time_t(mtime_ts);
3556 910 : atime = convert_timespec_to_time_t(atime_ts);
3557 910 : c_time = convert_timespec_to_time_t(ctime_ts);
3558 :
3559 910 : p = strrchr_m(smb_fname->base_name,'/');
3560 910 : if (!p)
3561 527 : base_name = smb_fname->base_name;
3562 : else
3563 383 : base_name = p+1;
3564 :
3565 : /* NT expects the name to be in an exact form of the *full*
3566 : filename. See the trans2 torture test */
3567 910 : if (ISDOT(base_name)) {
3568 40 : dos_fname = talloc_strdup(mem_ctx, "\\");
3569 60 : if (!dos_fname) {
3570 0 : return NT_STATUS_NO_MEMORY;
3571 : }
3572 : } else {
3573 870 : dos_fname = talloc_asprintf(mem_ctx,
3574 : "\\%s",
3575 : smb_fname->base_name);
3576 870 : if (!dos_fname) {
3577 0 : return NT_STATUS_NO_MEMORY;
3578 : }
3579 870 : if (is_named_stream(smb_fname)) {
3580 24 : dos_fname = talloc_asprintf(dos_fname, "%s",
3581 : smb_fname->stream_name);
3582 24 : if (!dos_fname) {
3583 0 : return NT_STATUS_NO_MEMORY;
3584 : }
3585 : }
3586 :
3587 870 : string_replace(dos_fname, '/', '\\');
3588 : }
3589 :
3590 910 : allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp, psbuf);
3591 :
3592 910 : if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
3593 : /* Do we have this path open ? */
3594 : files_struct *fsp1;
3595 0 : struct file_id fileid = vfs_file_id_from_sbuf(conn, psbuf);
3596 0 : fsp1 = file_find_di_first(conn->sconn, fileid, true);
3597 0 : if (fsp1 && fsp1->initial_allocation_size) {
3598 0 : allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, fsp1, psbuf);
3599 : }
3600 : }
3601 :
3602 910 : if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) {
3603 827 : file_size = get_file_size_stat(psbuf);
3604 : }
3605 :
3606 910 : if (fsp) {
3607 910 : pos = fh_get_position_information(fsp->fh);
3608 : }
3609 :
3610 910 : if (fsp) {
3611 910 : access_mask = fsp->access_mask;
3612 : } else {
3613 : /* GENERIC_EXECUTE mapping from Windows */
3614 0 : access_mask = 0x12019F;
3615 : }
3616 :
3617 : /* This should be an index number - looks like
3618 : dev/ino to me :-)
3619 :
3620 : I think this causes us to fail the IFSKIT
3621 : BasicFileInformationTest. -tpot */
3622 910 : file_id = SMB_VFS_FS_FILE_ID(conn, base_sp);
3623 :
3624 910 : *fixed_portion = 0;
3625 :
3626 910 : switch (info_level) {
3627 0 : case SMB_INFO_STANDARD:
3628 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
3629 0 : data_size = 22;
3630 0 : srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
3631 0 : srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
3632 0 : srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
3633 0 : SIVAL(pdata,l1_cbFile,(uint32_t)file_size);
3634 0 : SIVAL(pdata,l1_cbFileAlloc,(uint32_t)allocation_size);
3635 0 : SSVAL(pdata,l1_attrFile,mode);
3636 0 : break;
3637 :
3638 0 : case SMB_INFO_QUERY_EA_SIZE:
3639 : {
3640 0 : unsigned int ea_size =
3641 0 : estimate_ea_size(smb_fname->fsp);
3642 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
3643 0 : data_size = 26;
3644 0 : srv_put_dos_date2(pdata,0,create_time);
3645 0 : srv_put_dos_date2(pdata,4,atime);
3646 0 : srv_put_dos_date2(pdata,8,mtime); /* write time */
3647 0 : SIVAL(pdata,12,(uint32_t)file_size);
3648 0 : SIVAL(pdata,16,(uint32_t)allocation_size);
3649 0 : SSVAL(pdata,20,mode);
3650 0 : SIVAL(pdata,22,ea_size);
3651 0 : break;
3652 : }
3653 :
3654 0 : case SMB_INFO_IS_NAME_VALID:
3655 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
3656 0 : if (fsp) {
3657 : /* os/2 needs this ? really ?*/
3658 0 : return NT_STATUS_DOS(ERRDOS, ERRbadfunc);
3659 : }
3660 : /* This is only reached for qpathinfo */
3661 0 : data_size = 0;
3662 0 : break;
3663 :
3664 0 : case SMB_INFO_QUERY_EAS_FROM_LIST:
3665 : {
3666 0 : size_t total_ea_len = 0;
3667 0 : struct ea_list *ea_file_list = NULL;
3668 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
3669 :
3670 0 : status =
3671 0 : get_ea_list_from_fsp(mem_ctx,
3672 0 : smb_fname->fsp,
3673 : &total_ea_len, &ea_file_list);
3674 0 : if (!NT_STATUS_IS_OK(status)) {
3675 0 : return status;
3676 : }
3677 :
3678 0 : ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
3679 :
3680 0 : if (!ea_list || (total_ea_len > data_size)) {
3681 0 : data_size = 4;
3682 0 : SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
3683 0 : break;
3684 : }
3685 :
3686 0 : data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
3687 0 : break;
3688 : }
3689 :
3690 0 : case SMB_INFO_QUERY_ALL_EAS:
3691 : {
3692 : /* We have data_size bytes to put EA's into. */
3693 0 : size_t total_ea_len = 0;
3694 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
3695 :
3696 0 : status = get_ea_list_from_fsp(mem_ctx,
3697 0 : smb_fname->fsp,
3698 : &total_ea_len, &ea_list);
3699 0 : if (!NT_STATUS_IS_OK(status)) {
3700 0 : return status;
3701 : }
3702 :
3703 0 : if (!ea_list || (total_ea_len > data_size)) {
3704 0 : data_size = 4;
3705 0 : SIVAL(pdata,0,4); /* EA List Length must be set to 4 if no EA's. */
3706 0 : break;
3707 : }
3708 :
3709 0 : data_size = fill_ea_buffer(mem_ctx, pdata, data_size, conn, ea_list);
3710 0 : break;
3711 : }
3712 :
3713 0 : case SMB2_FILE_FULL_EA_INFORMATION:
3714 : {
3715 : /* We have data_size bytes to put EA's into. */
3716 0 : size_t total_ea_len = 0;
3717 0 : struct ea_list *ea_file_list = NULL;
3718 :
3719 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB2_INFO_QUERY_ALL_EAS\n"));
3720 :
3721 : /*TODO: add filtering and index handling */
3722 :
3723 0 : status =
3724 0 : get_ea_list_from_fsp(mem_ctx,
3725 0 : smb_fname->fsp,
3726 : &total_ea_len, &ea_file_list);
3727 0 : if (!NT_STATUS_IS_OK(status)) {
3728 0 : return status;
3729 : }
3730 0 : if (!ea_file_list) {
3731 0 : return NT_STATUS_NO_EAS_ON_FILE;
3732 : }
3733 :
3734 0 : status = fill_ea_chained_buffer(mem_ctx,
3735 : pdata,
3736 : data_size,
3737 : &data_size,
3738 : conn, ea_file_list);
3739 0 : if (!NT_STATUS_IS_OK(status)) {
3740 0 : return status;
3741 : }
3742 0 : break;
3743 : }
3744 :
3745 0 : case SMB_FILE_BASIC_INFORMATION:
3746 : case SMB_QUERY_FILE_BASIC_INFO:
3747 :
3748 0 : if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
3749 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
3750 0 : data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
3751 : } else {
3752 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
3753 0 : data_size = 40;
3754 0 : SIVAL(pdata,36,0);
3755 : }
3756 0 : put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
3757 0 : put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
3758 0 : put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
3759 0 : put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
3760 0 : SIVAL(pdata,32,mode);
3761 :
3762 0 : DEBUG(5,("SMB_QFBI - "));
3763 0 : DEBUG(5,("create: %s ", ctime(&create_time)));
3764 0 : DEBUG(5,("access: %s ", ctime(&atime)));
3765 0 : DEBUG(5,("write: %s ", ctime(&mtime)));
3766 0 : DEBUG(5,("change: %s ", ctime(&c_time)));
3767 0 : DEBUG(5,("mode: %x\n", mode));
3768 0 : *fixed_portion = data_size;
3769 0 : break;
3770 :
3771 0 : case SMB_FILE_STANDARD_INFORMATION:
3772 : case SMB_QUERY_FILE_STANDARD_INFO:
3773 :
3774 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
3775 0 : data_size = 24;
3776 0 : SOFF_T(pdata,0,allocation_size);
3777 0 : SOFF_T(pdata,8,file_size);
3778 0 : SIVAL(pdata,16,nlink);
3779 0 : SCVAL(pdata,20,delete_pending?1:0);
3780 0 : SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
3781 0 : SSVAL(pdata,22,0); /* Padding. */
3782 0 : *fixed_portion = 24;
3783 0 : break;
3784 :
3785 0 : case SMB_FILE_EA_INFORMATION:
3786 : case SMB_QUERY_FILE_EA_INFO:
3787 : {
3788 0 : unsigned int ea_size =
3789 0 : estimate_ea_size(smb_fname->fsp);
3790 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
3791 0 : data_size = 4;
3792 0 : *fixed_portion = 4;
3793 0 : SIVAL(pdata,0,ea_size);
3794 0 : break;
3795 : }
3796 :
3797 : /* Get the 8.3 name - used if NT SMB was negotiated. */
3798 52 : case SMB_QUERY_FILE_ALT_NAME_INFO:
3799 : case SMB_FILE_ALTERNATE_NAME_INFORMATION:
3800 : {
3801 : char mangled_name[13];
3802 52 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
3803 52 : if (!name_to_8_3(base_name,mangled_name,
3804 52 : True,conn->params)) {
3805 0 : return NT_STATUS_NO_MEMORY;
3806 : }
3807 52 : status = srvstr_push(dstart, flags2,
3808 : pdata+4, mangled_name,
3809 : PTR_DIFF(dend, pdata+4),
3810 : STR_UNICODE, &len);
3811 52 : if (!NT_STATUS_IS_OK(status)) {
3812 0 : return status;
3813 : }
3814 52 : data_size = 4 + len;
3815 52 : SIVAL(pdata,0,len);
3816 52 : *fixed_portion = 8;
3817 52 : break;
3818 : }
3819 :
3820 0 : case SMB_QUERY_FILE_NAME_INFO:
3821 : {
3822 : /*
3823 : this must be *exactly* right for ACLs on mapped drives to work
3824 : */
3825 0 : status = srvstr_push(dstart, flags2,
3826 : pdata+4, dos_fname,
3827 : PTR_DIFF(dend, pdata+4),
3828 : STR_UNICODE, &len);
3829 0 : if (!NT_STATUS_IS_OK(status)) {
3830 0 : return status;
3831 : }
3832 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
3833 0 : data_size = 4 + len;
3834 0 : SIVAL(pdata,0,len);
3835 0 : break;
3836 : }
3837 :
3838 0 : case SMB_FILE_NORMALIZED_NAME_INFORMATION:
3839 : {
3840 0 : char *nfname = NULL;
3841 :
3842 0 : if (fsp == NULL || !fsp->conn->sconn->using_smb2) {
3843 0 : return NT_STATUS_INVALID_LEVEL;
3844 : }
3845 :
3846 0 : nfname = talloc_strdup(mem_ctx, smb_fname->base_name);
3847 0 : if (nfname == NULL) {
3848 0 : return NT_STATUS_NO_MEMORY;
3849 : }
3850 :
3851 0 : if (ISDOT(nfname)) {
3852 0 : nfname[0] = '\0';
3853 : }
3854 0 : string_replace(nfname, '/', '\\');
3855 :
3856 0 : if (fsp_is_alternate_stream(fsp)) {
3857 0 : const char *s = smb_fname->stream_name;
3858 0 : const char *e = NULL;
3859 : size_t n;
3860 :
3861 0 : SMB_ASSERT(s[0] != '\0');
3862 :
3863 : /*
3864 : * smb_fname->stream_name is in form
3865 : * of ':StrEam:$DATA', but we should only
3866 : * append ':StrEam' here.
3867 : */
3868 :
3869 0 : e = strchr(&s[1], ':');
3870 0 : if (e == NULL) {
3871 0 : n = strlen(s);
3872 : } else {
3873 0 : n = PTR_DIFF(e, s);
3874 : }
3875 0 : nfname = talloc_strndup_append(nfname, s, n);
3876 0 : if (nfname == NULL) {
3877 0 : return NT_STATUS_NO_MEMORY;
3878 : }
3879 : }
3880 :
3881 0 : status = srvstr_push(dstart, flags2,
3882 : pdata+4, nfname,
3883 : PTR_DIFF(dend, pdata+4),
3884 : STR_UNICODE, &len);
3885 0 : if (!NT_STATUS_IS_OK(status)) {
3886 0 : return status;
3887 : }
3888 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NORMALIZED_NAME_INFORMATION\n"));
3889 0 : data_size = 4 + len;
3890 0 : SIVAL(pdata,0,len);
3891 0 : *fixed_portion = 8;
3892 0 : break;
3893 : }
3894 :
3895 0 : case SMB_FILE_ALLOCATION_INFORMATION:
3896 : case SMB_QUERY_FILE_ALLOCATION_INFO:
3897 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
3898 0 : data_size = 8;
3899 0 : SOFF_T(pdata,0,allocation_size);
3900 0 : break;
3901 :
3902 0 : case SMB_FILE_END_OF_FILE_INFORMATION:
3903 : case SMB_QUERY_FILE_END_OF_FILEINFO:
3904 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
3905 0 : data_size = 8;
3906 0 : SOFF_T(pdata,0,file_size);
3907 0 : break;
3908 :
3909 0 : case SMB_QUERY_FILE_ALL_INFO:
3910 : case SMB_FILE_ALL_INFORMATION:
3911 : {
3912 0 : unsigned int ea_size =
3913 0 : estimate_ea_size(smb_fname->fsp);
3914 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
3915 0 : put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
3916 0 : put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
3917 0 : put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
3918 0 : put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
3919 0 : SIVAL(pdata,32,mode);
3920 0 : SIVAL(pdata,36,0); /* padding. */
3921 0 : pdata += 40;
3922 0 : SOFF_T(pdata,0,allocation_size);
3923 0 : SOFF_T(pdata,8,file_size);
3924 0 : SIVAL(pdata,16,nlink);
3925 0 : SCVAL(pdata,20,delete_pending);
3926 0 : SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
3927 0 : SSVAL(pdata,22,0);
3928 0 : pdata += 24;
3929 0 : SIVAL(pdata,0,ea_size);
3930 0 : pdata += 4; /* EA info */
3931 0 : status = srvstr_push(dstart, flags2,
3932 : pdata+4, dos_fname,
3933 : PTR_DIFF(dend, pdata+4),
3934 : STR_UNICODE, &len);
3935 0 : if (!NT_STATUS_IS_OK(status)) {
3936 0 : return status;
3937 : }
3938 0 : SIVAL(pdata,0,len);
3939 0 : pdata += 4 + len;
3940 0 : data_size = PTR_DIFF(pdata,(*ppdata));
3941 0 : *fixed_portion = 10;
3942 0 : break;
3943 : }
3944 :
3945 498 : case SMB2_FILE_ALL_INFORMATION:
3946 : {
3947 440 : unsigned int ea_size =
3948 498 : estimate_ea_size(smb_fname->fsp);
3949 498 : DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
3950 498 : put_long_date_full_timespec(conn->ts_res,pdata+0x00,&create_time_ts);
3951 498 : put_long_date_full_timespec(conn->ts_res,pdata+0x08,&atime_ts);
3952 498 : put_long_date_full_timespec(conn->ts_res,pdata+0x10,&mtime_ts); /* write time */
3953 498 : put_long_date_full_timespec(conn->ts_res,pdata+0x18,&ctime_ts); /* change time */
3954 498 : SIVAL(pdata, 0x20, mode);
3955 498 : SIVAL(pdata, 0x24, 0); /* padding. */
3956 498 : SBVAL(pdata, 0x28, allocation_size);
3957 498 : SBVAL(pdata, 0x30, file_size);
3958 498 : SIVAL(pdata, 0x38, nlink);
3959 498 : SCVAL(pdata, 0x3C, delete_pending);
3960 498 : SCVAL(pdata, 0x3D, (mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
3961 498 : SSVAL(pdata, 0x3E, 0); /* padding */
3962 498 : SBVAL(pdata, 0x40, file_id);
3963 498 : SIVAL(pdata, 0x48, ea_size);
3964 498 : SIVAL(pdata, 0x4C, access_mask);
3965 498 : SBVAL(pdata, 0x50, pos);
3966 498 : SIVAL(pdata, 0x58, mode); /*TODO: mode != mode fix this!!! */
3967 498 : SIVAL(pdata, 0x5C, 0); /* No alignment needed. */
3968 :
3969 498 : pdata += 0x60;
3970 :
3971 498 : status = srvstr_push(dstart, flags2,
3972 : pdata+4, dos_fname,
3973 : PTR_DIFF(dend, pdata+4),
3974 : STR_UNICODE, &len);
3975 498 : if (!NT_STATUS_IS_OK(status)) {
3976 0 : return status;
3977 : }
3978 498 : SIVAL(pdata,0,len);
3979 498 : pdata += 4 + len;
3980 498 : data_size = PTR_DIFF(pdata,(*ppdata));
3981 498 : *fixed_portion = 104;
3982 498 : break;
3983 : }
3984 0 : case SMB_FILE_INTERNAL_INFORMATION:
3985 :
3986 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
3987 0 : SBVAL(pdata, 0, file_id);
3988 0 : data_size = 8;
3989 0 : *fixed_portion = 8;
3990 0 : break;
3991 :
3992 30 : case SMB_FILE_ACCESS_INFORMATION:
3993 30 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
3994 30 : SIVAL(pdata, 0, access_mask);
3995 30 : data_size = 4;
3996 30 : *fixed_portion = 4;
3997 30 : break;
3998 :
3999 0 : case SMB_FILE_NAME_INFORMATION:
4000 : /* Pathname with leading '\'. */
4001 : {
4002 : size_t byte_len;
4003 0 : byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
4004 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
4005 0 : SIVAL(pdata,0,byte_len);
4006 0 : data_size = 4 + byte_len;
4007 0 : break;
4008 : }
4009 :
4010 0 : case SMB_FILE_DISPOSITION_INFORMATION:
4011 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
4012 0 : data_size = 1;
4013 0 : SCVAL(pdata,0,delete_pending);
4014 0 : *fixed_portion = 1;
4015 0 : break;
4016 :
4017 278 : case SMB_FILE_POSITION_INFORMATION:
4018 278 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
4019 278 : data_size = 8;
4020 278 : SOFF_T(pdata,0,pos);
4021 278 : *fixed_portion = 8;
4022 278 : break;
4023 :
4024 0 : case SMB_FILE_MODE_INFORMATION:
4025 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
4026 0 : SIVAL(pdata,0,mode);
4027 0 : data_size = 4;
4028 0 : *fixed_portion = 4;
4029 0 : break;
4030 :
4031 0 : case SMB_FILE_ALIGNMENT_INFORMATION:
4032 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
4033 0 : SIVAL(pdata,0,0); /* No alignment needed. */
4034 0 : data_size = 4;
4035 0 : *fixed_portion = 4;
4036 0 : break;
4037 :
4038 : /*
4039 : * NT4 server just returns "invalid query" to this - if we try
4040 : * to answer it then NTws gets a BSOD! (tridge). W2K seems to
4041 : * want this. JRA.
4042 : */
4043 : /* The first statement above is false - verified using Thursby
4044 : * client against NT4 -- gcolley.
4045 : */
4046 52 : case SMB_QUERY_FILE_STREAM_INFO:
4047 : case SMB_FILE_STREAM_INFORMATION: {
4048 52 : unsigned int num_streams = 0;
4049 52 : struct stream_struct *streams = NULL;
4050 :
4051 52 : DEBUG(10,("smbd_do_qfilepathinfo: "
4052 : "SMB_FILE_STREAM_INFORMATION\n"));
4053 :
4054 52 : if (is_ntfs_stream_smb_fname(smb_fname)) {
4055 12 : return NT_STATUS_INVALID_PARAMETER;
4056 : }
4057 :
4058 44 : status = vfs_fstreaminfo(fsp,
4059 : mem_ctx,
4060 : &num_streams,
4061 : &streams);
4062 :
4063 44 : if (!NT_STATUS_IS_OK(status)) {
4064 0 : DEBUG(10, ("could not get stream info: %s\n",
4065 : nt_errstr(status)));
4066 0 : return status;
4067 : }
4068 :
4069 44 : status = marshall_stream_info(num_streams, streams,
4070 : pdata, max_data_bytes,
4071 : &data_size);
4072 :
4073 44 : if (!NT_STATUS_IS_OK(status)) {
4074 0 : DEBUG(10, ("marshall_stream_info failed: %s\n",
4075 : nt_errstr(status)));
4076 0 : TALLOC_FREE(streams);
4077 0 : return status;
4078 : }
4079 :
4080 44 : TALLOC_FREE(streams);
4081 :
4082 44 : *fixed_portion = 32;
4083 :
4084 44 : break;
4085 : }
4086 0 : case SMB_QUERY_COMPRESSION_INFO:
4087 : case SMB_FILE_COMPRESSION_INFORMATION:
4088 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
4089 0 : SOFF_T(pdata,0,file_size);
4090 0 : SIVAL(pdata,8,0); /* ??? */
4091 0 : SIVAL(pdata,12,0); /* ??? */
4092 0 : data_size = 16;
4093 0 : *fixed_portion = 16;
4094 0 : break;
4095 :
4096 0 : case SMB_FILE_NETWORK_OPEN_INFORMATION:
4097 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
4098 0 : put_long_date_full_timespec(conn->ts_res,pdata,&create_time_ts);
4099 0 : put_long_date_full_timespec(conn->ts_res,pdata+8,&atime_ts);
4100 0 : put_long_date_full_timespec(conn->ts_res,pdata+16,&mtime_ts); /* write time */
4101 0 : put_long_date_full_timespec(conn->ts_res,pdata+24,&ctime_ts); /* change time */
4102 0 : SOFF_T(pdata,32,allocation_size);
4103 0 : SOFF_T(pdata,40,file_size);
4104 0 : SIVAL(pdata,48,mode);
4105 0 : SIVAL(pdata,52,0); /* ??? */
4106 0 : data_size = 56;
4107 0 : *fixed_portion = 56;
4108 0 : break;
4109 :
4110 0 : case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
4111 0 : DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
4112 0 : SIVAL(pdata,0,mode);
4113 0 : SIVAL(pdata,4,0);
4114 0 : data_size = 8;
4115 0 : *fixed_portion = 8;
4116 0 : break;
4117 :
4118 : /*
4119 : * CIFS UNIX Extensions.
4120 : */
4121 :
4122 0 : case SMB_QUERY_FILE_UNIX_BASIC:
4123 :
4124 0 : pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
4125 0 : data_size = PTR_DIFF(pdata,(*ppdata));
4126 :
4127 0 : DEBUG(4,("smbd_do_qfilepathinfo: "
4128 : "SMB_QUERY_FILE_UNIX_BASIC\n"));
4129 0 : dump_data(4, (uint8_t *)(*ppdata), data_size);
4130 :
4131 0 : break;
4132 :
4133 0 : case SMB_QUERY_FILE_UNIX_INFO2:
4134 :
4135 0 : pdata = store_file_unix_basic_info2(conn, pdata, fsp, psbuf);
4136 0 : data_size = PTR_DIFF(pdata,(*ppdata));
4137 :
4138 : {
4139 : int i;
4140 0 : DEBUG(4,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));
4141 :
4142 0 : for (i=0; i<100; i++)
4143 0 : DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
4144 0 : DEBUG(4,("\n"));
4145 : }
4146 :
4147 0 : break;
4148 :
4149 0 : case SMB_QUERY_FILE_UNIX_LINK:
4150 : {
4151 0 : status = smb_unix_read_symlink(conn,
4152 : req,
4153 : smb_fname,
4154 : pdata,
4155 : data_size,
4156 : &data_size);
4157 0 : if (!NT_STATUS_IS_OK(status)) {
4158 0 : return status;
4159 : }
4160 0 : break;
4161 : }
4162 :
4163 : #if defined(HAVE_POSIX_ACLS)
4164 0 : case SMB_QUERY_POSIX_ACL:
4165 : {
4166 0 : status = smb_query_posix_acl(conn,
4167 : req,
4168 : fsp,
4169 : smb_fname,
4170 : pdata,
4171 : data_size,
4172 : &data_size);
4173 0 : if (!NT_STATUS_IS_OK(status)) {
4174 0 : return status;
4175 : }
4176 0 : break;
4177 : }
4178 : #endif
4179 :
4180 :
4181 0 : case SMB_QUERY_POSIX_LOCK:
4182 : {
4183 : uint64_t count;
4184 : uint64_t offset;
4185 : uint64_t smblctx;
4186 : enum brl_type lock_type;
4187 :
4188 : /* We need an open file with a real fd for this. */
4189 0 : if (fsp == NULL ||
4190 0 : fsp->fsp_flags.is_pathref ||
4191 0 : fsp_get_io_fd(fsp) == -1)
4192 : {
4193 0 : return NT_STATUS_INVALID_LEVEL;
4194 : }
4195 :
4196 0 : if (lock_data_count != POSIX_LOCK_DATA_SIZE) {
4197 0 : return NT_STATUS_INVALID_PARAMETER;
4198 : }
4199 :
4200 0 : switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
4201 0 : case POSIX_LOCK_TYPE_READ:
4202 0 : lock_type = READ_LOCK;
4203 0 : break;
4204 0 : case POSIX_LOCK_TYPE_WRITE:
4205 0 : lock_type = WRITE_LOCK;
4206 0 : break;
4207 0 : case POSIX_LOCK_TYPE_UNLOCK:
4208 : default:
4209 : /* There's no point in asking for an unlock... */
4210 0 : return NT_STATUS_INVALID_PARAMETER;
4211 : }
4212 :
4213 0 : smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
4214 0 : offset = BVAL(pdata,POSIX_LOCK_START_OFFSET);
4215 0 : count = BVAL(pdata,POSIX_LOCK_LEN_OFFSET);
4216 :
4217 0 : status = query_lock(fsp,
4218 : &smblctx,
4219 : &count,
4220 : &offset,
4221 : &lock_type,
4222 : POSIX_LOCK);
4223 :
4224 0 : if (ERROR_WAS_LOCK_DENIED(status)) {
4225 : /* Here we need to report who has it locked... */
4226 0 : data_size = POSIX_LOCK_DATA_SIZE;
4227 :
4228 0 : SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
4229 0 : SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
4230 0 : SIVAL(pdata, POSIX_LOCK_PID_OFFSET, (uint32_t)smblctx);
4231 0 : SBVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
4232 0 : SBVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
4233 :
4234 0 : } else if (NT_STATUS_IS_OK(status)) {
4235 : /* For success we just return a copy of what we sent
4236 : with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
4237 0 : data_size = POSIX_LOCK_DATA_SIZE;
4238 0 : memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
4239 0 : SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
4240 : } else {
4241 0 : return status;
4242 : }
4243 0 : break;
4244 : }
4245 :
4246 0 : default:
4247 0 : return NT_STATUS_INVALID_LEVEL;
4248 : }
4249 :
4250 902 : *pdata_size = data_size;
4251 902 : return NT_STATUS_OK;
4252 : }
4253 :
4254 : /****************************************************************************
4255 : Set a hard link (called by UNIX extensions and by NT rename with HARD link
4256 : code.
4257 : ****************************************************************************/
4258 :
4259 4 : NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
4260 : connection_struct *conn,
4261 : struct smb_request *req,
4262 : bool overwrite_if_exists,
4263 : struct files_struct *old_dirfsp,
4264 : const struct smb_filename *smb_fname_old,
4265 : struct files_struct *new_dirfsp,
4266 : struct smb_filename *smb_fname_new)
4267 : {
4268 4 : NTSTATUS status = NT_STATUS_OK;
4269 : int ret;
4270 : bool ok;
4271 4 : struct smb_filename *parent_fname_old = NULL;
4272 4 : struct smb_filename *base_name_old = NULL;
4273 4 : struct smb_filename *parent_fname_new = NULL;
4274 4 : struct smb_filename *base_name_new = NULL;
4275 :
4276 : /* source must already exist. */
4277 4 : if (!VALID_STAT(smb_fname_old->st)) {
4278 0 : status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
4279 0 : goto out;
4280 : }
4281 :
4282 : /* No links from a directory. */
4283 4 : if (S_ISDIR(smb_fname_old->st.st_ex_mode)) {
4284 0 : status = NT_STATUS_FILE_IS_A_DIRECTORY;
4285 0 : goto out;
4286 : }
4287 :
4288 : /* Setting a hardlink to/from a stream isn't currently supported. */
4289 4 : ok = is_ntfs_stream_smb_fname(smb_fname_old);
4290 4 : if (ok) {
4291 0 : DBG_DEBUG("Old name has streams\n");
4292 0 : status = NT_STATUS_INVALID_PARAMETER;
4293 0 : goto out;
4294 : }
4295 4 : ok = is_ntfs_stream_smb_fname(smb_fname_new);
4296 4 : if (ok) {
4297 0 : DBG_DEBUG("New name has streams\n");
4298 0 : status = NT_STATUS_INVALID_PARAMETER;
4299 0 : goto out;
4300 : }
4301 :
4302 4 : status = parent_pathref(talloc_tos(),
4303 : conn->cwd_fsp,
4304 : smb_fname_old,
4305 : &parent_fname_old,
4306 : &base_name_old);
4307 4 : if (!NT_STATUS_IS_OK(status)) {
4308 0 : goto out;
4309 : }
4310 :
4311 4 : status = parent_pathref(talloc_tos(),
4312 : conn->cwd_fsp,
4313 : smb_fname_new,
4314 : &parent_fname_new,
4315 : &base_name_new);
4316 4 : if (!NT_STATUS_IS_OK(status)) {
4317 0 : goto out;
4318 : }
4319 :
4320 4 : if (VALID_STAT(smb_fname_new->st)) {
4321 0 : if (overwrite_if_exists) {
4322 0 : if (S_ISDIR(smb_fname_new->st.st_ex_mode)) {
4323 0 : status = NT_STATUS_FILE_IS_A_DIRECTORY;
4324 0 : goto out;
4325 : }
4326 0 : status = unlink_internals(conn,
4327 : req,
4328 : FILE_ATTRIBUTE_NORMAL,
4329 : NULL, /* new_dirfsp */
4330 : smb_fname_new);
4331 0 : if (!NT_STATUS_IS_OK(status)) {
4332 0 : goto out;
4333 : }
4334 : } else {
4335 : /* Disallow if newname already exists. */
4336 0 : status = NT_STATUS_OBJECT_NAME_COLLISION;
4337 0 : goto out;
4338 : }
4339 : }
4340 :
4341 4 : DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n",
4342 : smb_fname_old->base_name, smb_fname_new->base_name));
4343 :
4344 4 : ret = SMB_VFS_LINKAT(conn,
4345 : parent_fname_old->fsp,
4346 : base_name_old,
4347 : parent_fname_new->fsp,
4348 : base_name_new,
4349 : 0);
4350 :
4351 4 : if (ret != 0) {
4352 0 : status = map_nt_error_from_unix(errno);
4353 0 : DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
4354 : nt_errstr(status), smb_fname_old->base_name,
4355 : smb_fname_new->base_name));
4356 : }
4357 :
4358 6 : out:
4359 :
4360 4 : TALLOC_FREE(parent_fname_old);
4361 4 : TALLOC_FREE(parent_fname_new);
4362 4 : return status;
4363 : }
4364 :
4365 : /****************************************************************************
4366 : Deal with setting the time from any of the setfilepathinfo functions.
4367 : NOTE !!!! The check for FILE_WRITE_ATTRIBUTES access must be done *before*
4368 : calling this function.
4369 : ****************************************************************************/
4370 :
4371 499 : NTSTATUS smb_set_file_time(connection_struct *conn,
4372 : files_struct *fsp,
4373 : struct smb_filename *smb_fname,
4374 : struct smb_file_time *ft,
4375 : bool setting_write_time)
4376 : {
4377 499 : struct files_struct *set_fsp = NULL;
4378 : struct timeval_buf tbuf[4];
4379 499 : uint32_t action =
4380 : FILE_NOTIFY_CHANGE_LAST_ACCESS
4381 : |FILE_NOTIFY_CHANGE_LAST_WRITE
4382 : |FILE_NOTIFY_CHANGE_CREATION;
4383 : int ret;
4384 :
4385 499 : if (!VALID_STAT(smb_fname->st)) {
4386 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4387 : }
4388 :
4389 499 : if (fsp == NULL) {
4390 : /* A symlink */
4391 0 : return NT_STATUS_OK;
4392 : }
4393 :
4394 499 : set_fsp = metadata_fsp(fsp);
4395 :
4396 : /* get some defaults (no modifications) if any info is zero or -1. */
4397 499 : if (is_omit_timespec(&ft->create_time)) {
4398 494 : action &= ~FILE_NOTIFY_CHANGE_CREATION;
4399 : }
4400 :
4401 499 : if (is_omit_timespec(&ft->atime)) {
4402 494 : action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
4403 : }
4404 :
4405 499 : if (is_omit_timespec(&ft->mtime)) {
4406 61 : action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
4407 : }
4408 :
4409 499 : if (!setting_write_time) {
4410 : /* ft->mtime comes from change time, not write time. */
4411 437 : action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
4412 : }
4413 :
4414 : /* Ensure the resolution is the correct for
4415 : * what we can store on this filesystem. */
4416 :
4417 499 : round_timespec(conn->ts_res, &ft->create_time);
4418 499 : round_timespec(conn->ts_res, &ft->ctime);
4419 499 : round_timespec(conn->ts_res, &ft->atime);
4420 499 : round_timespec(conn->ts_res, &ft->mtime);
4421 :
4422 499 : DBG_DEBUG("smb_set_filetime: actime: %s\n ",
4423 : timespec_string_buf(&ft->atime, true, &tbuf[0]));
4424 499 : DBG_DEBUG("smb_set_filetime: modtime: %s\n ",
4425 : timespec_string_buf(&ft->mtime, true, &tbuf[1]));
4426 499 : DBG_DEBUG("smb_set_filetime: ctime: %s\n ",
4427 : timespec_string_buf(&ft->ctime, true, &tbuf[2]));
4428 499 : DBG_DEBUG("smb_set_file_time: createtime: %s\n ",
4429 : timespec_string_buf(&ft->create_time, true, &tbuf[3]));
4430 :
4431 499 : if (setting_write_time) {
4432 : /*
4433 : * This was a Windows setfileinfo on an open file.
4434 : * NT does this a lot. We also need to
4435 : * set the time here, as it can be read by
4436 : * FindFirst/FindNext and with the patch for bug #2045
4437 : * in smbd/fileio.c it ensures that this timestamp is
4438 : * kept sticky even after a write. We save the request
4439 : * away and will set it on file close and after a write. JRA.
4440 : */
4441 :
4442 62 : DBG_DEBUG("setting pending modtime to %s\n",
4443 : timespec_string_buf(&ft->mtime, true, &tbuf[0]));
4444 :
4445 62 : if (set_fsp != NULL) {
4446 62 : set_sticky_write_time_fsp(set_fsp, ft->mtime);
4447 : } else {
4448 0 : set_sticky_write_time_path(
4449 0 : vfs_file_id_from_sbuf(conn, &smb_fname->st),
4450 : ft->mtime);
4451 : }
4452 : }
4453 :
4454 499 : DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
4455 :
4456 499 : ret = file_ntimes(conn, set_fsp, ft);
4457 499 : if (ret != 0) {
4458 0 : return map_nt_error_from_unix(errno);
4459 : }
4460 :
4461 499 : notify_fname(conn, NOTIFY_ACTION_MODIFIED, action,
4462 499 : smb_fname->base_name);
4463 499 : return NT_STATUS_OK;
4464 : }
4465 :
4466 : /****************************************************************************
4467 : Deal with setting the dosmode from any of the setfilepathinfo functions.
4468 : NB. The check for FILE_WRITE_ATTRIBUTES access on this path must have been
4469 : done before calling this function.
4470 : ****************************************************************************/
4471 :
4472 63 : static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
4473 : struct files_struct *fsp,
4474 : uint32_t dosmode)
4475 : {
4476 63 : struct files_struct *dos_fsp = NULL;
4477 : uint32_t current_dosmode;
4478 : int ret;
4479 :
4480 63 : if (!VALID_STAT(fsp->fsp_name->st)) {
4481 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4482 : }
4483 :
4484 63 : dos_fsp = metadata_fsp(fsp);
4485 :
4486 63 : if (dosmode != 0) {
4487 59 : if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
4488 33 : dosmode |= FILE_ATTRIBUTE_DIRECTORY;
4489 : } else {
4490 26 : dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
4491 : }
4492 : }
4493 :
4494 63 : DBG_DEBUG("dosmode: 0x%" PRIx32 "\n", dosmode);
4495 :
4496 : /* check the mode isn't different, before changing it */
4497 63 : if (dosmode == 0) {
4498 4 : return NT_STATUS_OK;
4499 : }
4500 59 : current_dosmode = fdos_mode(dos_fsp);
4501 59 : if (dosmode == current_dosmode) {
4502 28 : return NT_STATUS_OK;
4503 : }
4504 :
4505 31 : DBG_DEBUG("file %s : setting dos mode 0x%" PRIx32 "\n",
4506 : fsp_str_dbg(dos_fsp), dosmode);
4507 :
4508 31 : ret = file_set_dosmode(conn, dos_fsp->fsp_name, dosmode, NULL, false);
4509 31 : if (ret != 0) {
4510 1 : DBG_WARNING("file_set_dosmode of %s failed: %s\n",
4511 : fsp_str_dbg(dos_fsp), strerror(errno));
4512 1 : return map_nt_error_from_unix(errno);
4513 : }
4514 :
4515 30 : return NT_STATUS_OK;
4516 : }
4517 :
4518 : /****************************************************************************
4519 : Deal with setting the size from any of the setfilepathinfo functions.
4520 : ****************************************************************************/
4521 :
4522 0 : static NTSTATUS smb_set_file_size(connection_struct *conn,
4523 : struct smb_request *req,
4524 : files_struct *fsp,
4525 : struct smb_filename *smb_fname,
4526 : const SMB_STRUCT_STAT *psbuf,
4527 : off_t size,
4528 : bool fail_after_createfile)
4529 : {
4530 0 : NTSTATUS status = NT_STATUS_OK;
4531 0 : files_struct *new_fsp = NULL;
4532 :
4533 0 : if (!VALID_STAT(*psbuf)) {
4534 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
4535 : }
4536 :
4537 0 : DBG_INFO("size: %"PRIu64", file_size_stat=%"PRIu64"\n",
4538 : (uint64_t)size,
4539 : get_file_size_stat(psbuf));
4540 :
4541 0 : if (size == get_file_size_stat(psbuf)) {
4542 0 : if (fsp == NULL) {
4543 0 : return NT_STATUS_OK;
4544 : }
4545 0 : if (!fsp->fsp_flags.modified) {
4546 0 : return NT_STATUS_OK;
4547 : }
4548 0 : trigger_write_time_update_immediate(fsp);
4549 0 : return NT_STATUS_OK;
4550 : }
4551 :
4552 0 : DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n",
4553 : smb_fname_str_dbg(smb_fname), (double)size));
4554 :
4555 0 : if (fsp &&
4556 0 : !fsp->fsp_flags.is_pathref &&
4557 0 : fsp_get_io_fd(fsp) != -1)
4558 : {
4559 : /* Handle based call. */
4560 0 : if (!(fsp->access_mask & FILE_WRITE_DATA)) {
4561 0 : return NT_STATUS_ACCESS_DENIED;
4562 : }
4563 :
4564 0 : if (vfs_set_filelen(fsp, size) == -1) {
4565 0 : return map_nt_error_from_unix(errno);
4566 : }
4567 0 : trigger_write_time_update_immediate(fsp);
4568 0 : return NT_STATUS_OK;
4569 : }
4570 :
4571 0 : status = SMB_VFS_CREATE_FILE(
4572 : conn, /* conn */
4573 : req, /* req */
4574 : NULL, /* dirfsp */
4575 : smb_fname, /* fname */
4576 : FILE_WRITE_DATA, /* access_mask */
4577 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
4578 : FILE_SHARE_DELETE),
4579 : FILE_OPEN, /* create_disposition*/
4580 : 0, /* create_options */
4581 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
4582 : 0, /* oplock_request */
4583 : NULL, /* lease */
4584 : 0, /* allocation_size */
4585 : 0, /* private_flags */
4586 : NULL, /* sd */
4587 : NULL, /* ea_list */
4588 : &new_fsp, /* result */
4589 : NULL, /* pinfo */
4590 : NULL, NULL); /* create context */
4591 :
4592 0 : if (!NT_STATUS_IS_OK(status)) {
4593 : /* NB. We check for open_was_deferred in the caller. */
4594 0 : return status;
4595 : }
4596 :
4597 : /* See RAW-SFILEINFO-END-OF-FILE */
4598 0 : if (fail_after_createfile) {
4599 0 : close_file_free(req, &new_fsp, NORMAL_CLOSE);
4600 0 : return NT_STATUS_INVALID_LEVEL;
4601 : }
4602 :
4603 0 : if (vfs_set_filelen(new_fsp, size) == -1) {
4604 0 : status = map_nt_error_from_unix(errno);
4605 0 : close_file_free(req, &new_fsp, NORMAL_CLOSE);
4606 0 : return status;
4607 : }
4608 :
4609 0 : trigger_write_time_update_immediate(new_fsp);
4610 0 : close_file_free(req, &new_fsp, NORMAL_CLOSE);
4611 0 : return NT_STATUS_OK;
4612 : }
4613 :
4614 : /****************************************************************************
4615 : Deal with SMB_INFO_SET_EA.
4616 : ****************************************************************************/
4617 :
4618 0 : static NTSTATUS smb_info_set_ea(connection_struct *conn,
4619 : const char *pdata,
4620 : int total_data,
4621 : files_struct *fsp,
4622 : struct smb_filename *smb_fname)
4623 : {
4624 0 : struct ea_list *ea_list = NULL;
4625 0 : TALLOC_CTX *ctx = NULL;
4626 0 : NTSTATUS status = NT_STATUS_OK;
4627 :
4628 0 : if (total_data < 10) {
4629 :
4630 : /* OS/2 workplace shell seems to send SET_EA requests of "null"
4631 : length. They seem to have no effect. Bug #3212. JRA */
4632 :
4633 0 : if ((total_data == 4) && (IVAL(pdata,0) == 4)) {
4634 : /* We're done. We only get EA info in this call. */
4635 0 : return NT_STATUS_OK;
4636 : }
4637 :
4638 0 : return NT_STATUS_INVALID_PARAMETER;
4639 : }
4640 :
4641 0 : if (IVAL(pdata,0) > total_data) {
4642 0 : DEBUG(10,("smb_info_set_ea: bad total data size (%u) > %u\n",
4643 : IVAL(pdata,0), (unsigned int)total_data));
4644 0 : return NT_STATUS_INVALID_PARAMETER;
4645 : }
4646 :
4647 0 : ctx = talloc_tos();
4648 0 : ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
4649 0 : if (!ea_list) {
4650 0 : return NT_STATUS_INVALID_PARAMETER;
4651 : }
4652 :
4653 0 : if (fsp == NULL) {
4654 : /*
4655 : * The only way fsp can be NULL here is if
4656 : * smb_fname points at a symlink and
4657 : * and we're in POSIX context.
4658 : * Ensure this is the case.
4659 : *
4660 : * In this case we cannot set the EA.
4661 : */
4662 0 : SMB_ASSERT(smb_fname->flags & SMB_FILENAME_POSIX_PATH);
4663 0 : return NT_STATUS_ACCESS_DENIED;
4664 : }
4665 :
4666 0 : status = set_ea(conn, fsp, ea_list);
4667 :
4668 0 : return status;
4669 : }
4670 :
4671 : /****************************************************************************
4672 : Deal with SMB_FILE_FULL_EA_INFORMATION set.
4673 : ****************************************************************************/
4674 :
4675 0 : static NTSTATUS smb_set_file_full_ea_info(connection_struct *conn,
4676 : const char *pdata,
4677 : int total_data,
4678 : files_struct *fsp)
4679 : {
4680 0 : struct ea_list *ea_list = NULL;
4681 : NTSTATUS status;
4682 :
4683 0 : if (fsp == NULL) {
4684 0 : return NT_STATUS_INVALID_HANDLE;
4685 : }
4686 :
4687 0 : if (!lp_ea_support(SNUM(conn))) {
4688 0 : DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u but "
4689 : "EA's not supported.\n",
4690 : (unsigned int)total_data));
4691 0 : return NT_STATUS_EAS_NOT_SUPPORTED;
4692 : }
4693 :
4694 0 : if (total_data < 10) {
4695 0 : DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u "
4696 : "too small.\n",
4697 : (unsigned int)total_data));
4698 0 : return NT_STATUS_INVALID_PARAMETER;
4699 : }
4700 :
4701 0 : ea_list = read_nttrans_ea_list(talloc_tos(),
4702 : pdata,
4703 : total_data);
4704 :
4705 0 : if (!ea_list) {
4706 0 : return NT_STATUS_INVALID_PARAMETER;
4707 : }
4708 :
4709 0 : status = set_ea(conn, fsp, ea_list);
4710 :
4711 0 : DEBUG(10, ("smb_set_file_full_ea_info on file %s returned %s\n",
4712 : smb_fname_str_dbg(fsp->fsp_name),
4713 : nt_errstr(status) ));
4714 :
4715 0 : return status;
4716 : }
4717 :
4718 :
4719 : /****************************************************************************
4720 : Deal with SMB_SET_FILE_DISPOSITION_INFO.
4721 : ****************************************************************************/
4722 :
4723 806 : static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
4724 : const char *pdata,
4725 : int total_data,
4726 : files_struct *fsp,
4727 : struct smb_filename *smb_fname)
4728 : {
4729 806 : NTSTATUS status = NT_STATUS_OK;
4730 : bool delete_on_close;
4731 806 : uint32_t dosmode = 0;
4732 :
4733 806 : if (total_data < 1) {
4734 0 : return NT_STATUS_INVALID_PARAMETER;
4735 : }
4736 :
4737 806 : if (fsp == NULL) {
4738 0 : return NT_STATUS_INVALID_HANDLE;
4739 : }
4740 :
4741 806 : delete_on_close = (CVAL(pdata,0) ? True : False);
4742 806 : dosmode = fdos_mode(fsp);
4743 :
4744 806 : DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
4745 : "delete_on_close = %u\n",
4746 : smb_fname_str_dbg(smb_fname),
4747 : (unsigned int)dosmode,
4748 : (unsigned int)delete_on_close ));
4749 :
4750 806 : if (delete_on_close) {
4751 806 : status = can_set_delete_on_close(fsp, dosmode);
4752 806 : if (!NT_STATUS_IS_OK(status)) {
4753 4 : return status;
4754 : }
4755 : }
4756 :
4757 : /* The set is across all open files on this dev/inode pair. */
4758 802 : if (!set_delete_on_close(fsp, delete_on_close,
4759 802 : conn->session_info->security_token,
4760 802 : conn->session_info->unix_token)) {
4761 0 : return NT_STATUS_ACCESS_DENIED;
4762 : }
4763 802 : return NT_STATUS_OK;
4764 : }
4765 :
4766 : /****************************************************************************
4767 : Deal with SMB_FILE_POSITION_INFORMATION.
4768 : ****************************************************************************/
4769 :
4770 0 : static NTSTATUS smb_file_position_information(connection_struct *conn,
4771 : const char *pdata,
4772 : int total_data,
4773 : files_struct *fsp)
4774 : {
4775 : uint64_t position_information;
4776 :
4777 0 : if (total_data < 8) {
4778 0 : return NT_STATUS_INVALID_PARAMETER;
4779 : }
4780 :
4781 0 : if (fsp == NULL) {
4782 : /* Ignore on pathname based set. */
4783 0 : return NT_STATUS_OK;
4784 : }
4785 :
4786 0 : position_information = (uint64_t)IVAL(pdata,0);
4787 0 : position_information |= (((uint64_t)IVAL(pdata,4)) << 32);
4788 :
4789 0 : DEBUG(10,("smb_file_position_information: Set file position "
4790 : "information for file %s to %.0f\n", fsp_str_dbg(fsp),
4791 : (double)position_information));
4792 0 : fh_set_position_information(fsp->fh, position_information);
4793 0 : return NT_STATUS_OK;
4794 : }
4795 :
4796 : /****************************************************************************
4797 : Deal with SMB_FILE_MODE_INFORMATION.
4798 : ****************************************************************************/
4799 :
4800 0 : static NTSTATUS smb_file_mode_information(connection_struct *conn,
4801 : const char *pdata,
4802 : int total_data)
4803 : {
4804 : uint32_t mode;
4805 :
4806 0 : if (total_data < 4) {
4807 0 : return NT_STATUS_INVALID_PARAMETER;
4808 : }
4809 0 : mode = IVAL(pdata,0);
4810 0 : if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
4811 0 : return NT_STATUS_INVALID_PARAMETER;
4812 : }
4813 0 : return NT_STATUS_OK;
4814 : }
4815 :
4816 : /****************************************************************************
4817 : Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
4818 : ****************************************************************************/
4819 :
4820 0 : static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
4821 : struct smb_request *req,
4822 : const char *pdata,
4823 : int total_data,
4824 : struct smb_filename *new_smb_fname)
4825 : {
4826 0 : char *link_target = NULL;
4827 : struct smb_filename target_fname;
4828 0 : TALLOC_CTX *ctx = talloc_tos();
4829 : NTSTATUS status;
4830 : int ret;
4831 0 : struct smb_filename *parent_fname = NULL;
4832 0 : struct smb_filename *base_name = NULL;
4833 :
4834 : /* Set a symbolic link. */
4835 : /* Don't allow this if follow links is false. */
4836 :
4837 0 : if (total_data == 0) {
4838 0 : return NT_STATUS_INVALID_PARAMETER;
4839 : }
4840 :
4841 0 : if (!lp_follow_symlinks(SNUM(conn))) {
4842 0 : return NT_STATUS_ACCESS_DENIED;
4843 : }
4844 :
4845 0 : srvstr_pull_talloc(ctx, pdata, req->flags2, &link_target, pdata,
4846 : total_data, STR_TERMINATE);
4847 :
4848 0 : if (!link_target) {
4849 0 : return NT_STATUS_INVALID_PARAMETER;
4850 : }
4851 :
4852 0 : target_fname = (struct smb_filename) {
4853 : .base_name = link_target,
4854 : };
4855 :
4856 : /* Removes @GMT tokens if any */
4857 0 : status = canonicalize_snapshot_path(&target_fname, UCF_GMT_PATHNAME, 0);
4858 0 : if (!NT_STATUS_IS_OK(status)) {
4859 0 : return status;
4860 : }
4861 :
4862 0 : DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
4863 : new_smb_fname->base_name, link_target ));
4864 :
4865 0 : status = parent_pathref(talloc_tos(),
4866 : conn->cwd_fsp,
4867 : new_smb_fname,
4868 : &parent_fname,
4869 : &base_name);
4870 0 : if (!NT_STATUS_IS_OK(status)) {
4871 0 : return status;
4872 : }
4873 :
4874 0 : ret = SMB_VFS_SYMLINKAT(conn,
4875 : &target_fname,
4876 : parent_fname->fsp,
4877 : base_name);
4878 0 : if (ret != 0) {
4879 0 : TALLOC_FREE(parent_fname);
4880 0 : return map_nt_error_from_unix(errno);
4881 : }
4882 :
4883 0 : TALLOC_FREE(parent_fname);
4884 0 : return NT_STATUS_OK;
4885 : }
4886 :
4887 : /****************************************************************************
4888 : Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
4889 : ****************************************************************************/
4890 :
4891 0 : static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
4892 : struct smb_request *req,
4893 : const char *pdata, int total_data,
4894 : struct smb_filename *smb_fname_new)
4895 : {
4896 0 : char *oldname = NULL;
4897 0 : struct files_struct *src_dirfsp = NULL;
4898 0 : struct smb_filename *smb_fname_old = NULL;
4899 0 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4900 0 : NTTIME old_twrp = 0;
4901 0 : TALLOC_CTX *ctx = talloc_tos();
4902 0 : NTSTATUS status = NT_STATUS_OK;
4903 :
4904 : /* Set a hard link. */
4905 0 : if (total_data == 0) {
4906 0 : return NT_STATUS_INVALID_PARAMETER;
4907 : }
4908 :
4909 0 : if (req->posix_pathnames) {
4910 0 : srvstr_get_path_posix(ctx,
4911 : pdata,
4912 0 : req->flags2,
4913 : &oldname,
4914 : pdata,
4915 : total_data,
4916 : STR_TERMINATE,
4917 : &status);
4918 : } else {
4919 0 : srvstr_get_path(ctx,
4920 : pdata,
4921 0 : req->flags2,
4922 : &oldname,
4923 : pdata,
4924 : total_data,
4925 : STR_TERMINATE,
4926 : &status);
4927 : }
4928 0 : if (!NT_STATUS_IS_OK(status)) {
4929 0 : return status;
4930 : }
4931 :
4932 0 : DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
4933 : smb_fname_str_dbg(smb_fname_new), oldname));
4934 :
4935 0 : if (ucf_flags & UCF_GMT_PATHNAME) {
4936 0 : extract_snapshot_token(oldname, &old_twrp);
4937 : }
4938 0 : status = filename_convert_dirfsp(ctx,
4939 : conn,
4940 : oldname,
4941 : ucf_flags,
4942 : old_twrp,
4943 : &src_dirfsp,
4944 : &smb_fname_old);
4945 0 : if (!NT_STATUS_IS_OK(status)) {
4946 0 : return status;
4947 : }
4948 :
4949 0 : return hardlink_internals(ctx,
4950 : conn,
4951 : req,
4952 : false,
4953 : src_dirfsp,
4954 : smb_fname_old,
4955 : NULL, /* new_dirfsp */
4956 : smb_fname_new);
4957 : }
4958 :
4959 : /****************************************************************************
4960 : Deal with SMB2_FILE_RENAME_INFORMATION_INTERNAL
4961 : ****************************************************************************/
4962 :
4963 21 : static NTSTATUS smb2_file_rename_information(connection_struct *conn,
4964 : struct smb_request *req,
4965 : const char *pdata,
4966 : int total_data,
4967 : files_struct *fsp,
4968 : struct smb_filename *smb_fname_src)
4969 : {
4970 : bool overwrite;
4971 : uint32_t len;
4972 21 : char *newname = NULL;
4973 21 : struct files_struct *dst_dirfsp = NULL;
4974 21 : struct smb_filename *smb_fname_dst = NULL;
4975 21 : const char *dst_original_lcomp = NULL;
4976 21 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
4977 21 : NTTIME dst_twrp = 0;
4978 21 : NTSTATUS status = NT_STATUS_OK;
4979 21 : bool is_dfs = (req->flags2 & FLAGS2_DFS_PATHNAMES);
4980 21 : TALLOC_CTX *ctx = talloc_tos();
4981 :
4982 21 : if (!fsp) {
4983 0 : return NT_STATUS_INVALID_HANDLE;
4984 : }
4985 :
4986 21 : if (total_data < 20) {
4987 0 : return NT_STATUS_INVALID_PARAMETER;
4988 : }
4989 :
4990 21 : overwrite = (CVAL(pdata,0) ? True : False);
4991 21 : len = IVAL(pdata,16);
4992 :
4993 21 : if (len > (total_data - 20) || (len == 0)) {
4994 0 : return NT_STATUS_INVALID_PARAMETER;
4995 : }
4996 :
4997 21 : (void)srvstr_pull_talloc(ctx,
4998 : pdata,
4999 : req->flags2,
5000 : &newname,
5001 : &pdata[20],
5002 : len,
5003 : STR_TERMINATE);
5004 :
5005 21 : if (newname == NULL) {
5006 0 : return NT_STATUS_INVALID_PARAMETER;
5007 : }
5008 21 : status = check_path_syntax_smb2(newname, is_dfs);
5009 21 : if (!NT_STATUS_IS_OK(status)) {
5010 0 : return status;
5011 : }
5012 :
5013 21 : DEBUG(10,("smb2_file_rename_information: got name |%s|\n",
5014 : newname));
5015 :
5016 21 : if (newname[0] == ':') {
5017 : /* Create an smb_fname to call rename_internals_fsp() with. */
5018 0 : smb_fname_dst = synthetic_smb_fname(talloc_tos(),
5019 0 : fsp->base_fsp->fsp_name->base_name,
5020 : newname,
5021 : NULL,
5022 0 : fsp->base_fsp->fsp_name->twrp,
5023 0 : fsp->base_fsp->fsp_name->flags);
5024 0 : if (smb_fname_dst == NULL) {
5025 0 : status = NT_STATUS_NO_MEMORY;
5026 0 : goto out;
5027 : }
5028 : } else {
5029 21 : if (ucf_flags & UCF_GMT_PATHNAME) {
5030 0 : extract_snapshot_token(newname, &dst_twrp);
5031 : }
5032 21 : status = filename_convert_dirfsp(ctx,
5033 : conn,
5034 : newname,
5035 : ucf_flags,
5036 : dst_twrp,
5037 : &dst_dirfsp,
5038 : &smb_fname_dst);
5039 21 : if (!NT_STATUS_IS_OK(status)) {
5040 0 : goto out;
5041 : }
5042 : }
5043 :
5044 : /*
5045 : * Set the original last component, since
5046 : * rename_internals_fsp() requires it.
5047 : */
5048 21 : dst_original_lcomp = get_original_lcomp(smb_fname_dst,
5049 : conn,
5050 : newname,
5051 : ucf_flags);
5052 21 : if (dst_original_lcomp == NULL) {
5053 0 : status = NT_STATUS_NO_MEMORY;
5054 0 : goto out;
5055 : }
5056 :
5057 21 : DEBUG(10,("smb2_file_rename_information: "
5058 : "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
5059 : fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
5060 : smb_fname_str_dbg(smb_fname_dst)));
5061 21 : status = rename_internals_fsp(conn,
5062 : fsp,
5063 : NULL, /* dst_dirfsp */
5064 : smb_fname_dst,
5065 : dst_original_lcomp,
5066 : (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM),
5067 : overwrite);
5068 :
5069 21 : out:
5070 21 : TALLOC_FREE(smb_fname_dst);
5071 21 : return status;
5072 : }
5073 :
5074 4 : static NTSTATUS smb_file_link_information(connection_struct *conn,
5075 : struct smb_request *req,
5076 : const char *pdata,
5077 : int total_data,
5078 : files_struct *fsp,
5079 : struct smb_filename *smb_fname_src)
5080 : {
5081 : bool overwrite;
5082 : uint32_t len;
5083 4 : char *newname = NULL;
5084 4 : struct files_struct *dst_dirfsp = NULL;
5085 4 : struct smb_filename *smb_fname_dst = NULL;
5086 4 : NTSTATUS status = NT_STATUS_OK;
5087 4 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
5088 4 : NTTIME dst_twrp = 0;
5089 4 : TALLOC_CTX *ctx = talloc_tos();
5090 :
5091 4 : if (!fsp) {
5092 0 : return NT_STATUS_INVALID_HANDLE;
5093 : }
5094 :
5095 4 : if (total_data < 20) {
5096 0 : return NT_STATUS_INVALID_PARAMETER;
5097 : }
5098 :
5099 4 : overwrite = (CVAL(pdata,0) ? true : false);
5100 4 : len = IVAL(pdata,16);
5101 :
5102 4 : if (len > (total_data - 20) || (len == 0)) {
5103 0 : return NT_STATUS_INVALID_PARAMETER;
5104 : }
5105 :
5106 4 : if (smb_fname_src->flags & SMB_FILENAME_POSIX_PATH) {
5107 0 : srvstr_get_path_posix(ctx,
5108 : pdata,
5109 0 : req->flags2,
5110 : &newname,
5111 : &pdata[20],
5112 : len,
5113 : STR_TERMINATE,
5114 : &status);
5115 0 : ucf_flags |= UCF_POSIX_PATHNAMES;
5116 : } else {
5117 6 : srvstr_get_path(ctx,
5118 : pdata,
5119 4 : req->flags2,
5120 : &newname,
5121 : &pdata[20],
5122 : len,
5123 : STR_TERMINATE,
5124 : &status);
5125 : }
5126 4 : if (!NT_STATUS_IS_OK(status)) {
5127 0 : return status;
5128 : }
5129 :
5130 4 : DEBUG(10,("smb_file_link_information: got name |%s|\n",
5131 : newname));
5132 :
5133 4 : if (ucf_flags & UCF_GMT_PATHNAME) {
5134 0 : extract_snapshot_token(newname, &dst_twrp);
5135 : }
5136 4 : status = filename_convert_dirfsp(ctx,
5137 : conn,
5138 : newname,
5139 : ucf_flags,
5140 : dst_twrp,
5141 : &dst_dirfsp,
5142 : &smb_fname_dst);
5143 4 : if (!NT_STATUS_IS_OK(status)) {
5144 0 : return status;
5145 : }
5146 :
5147 4 : if (fsp->base_fsp) {
5148 : /* No stream names. */
5149 0 : return NT_STATUS_NOT_SUPPORTED;
5150 : }
5151 :
5152 4 : DEBUG(10,("smb_file_link_information: "
5153 : "SMB_FILE_LINK_INFORMATION (%s) %s -> %s\n",
5154 : fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
5155 : smb_fname_str_dbg(smb_fname_dst)));
5156 6 : status = hardlink_internals(ctx,
5157 : conn,
5158 : req,
5159 : overwrite,
5160 : NULL, /* src_dirfsp */
5161 4 : fsp->fsp_name,
5162 : dst_dirfsp, /* dst_dirfsp */
5163 : smb_fname_dst);
5164 :
5165 4 : TALLOC_FREE(smb_fname_dst);
5166 4 : return status;
5167 : }
5168 :
5169 : /****************************************************************************
5170 : Deal with SMB_FILE_RENAME_INFORMATION.
5171 : ****************************************************************************/
5172 :
5173 0 : static NTSTATUS smb_file_rename_information(connection_struct *conn,
5174 : struct smb_request *req,
5175 : const char *pdata,
5176 : int total_data,
5177 : files_struct *fsp,
5178 : struct smb_filename *smb_fname_src)
5179 : {
5180 : bool overwrite;
5181 : uint32_t root_fid;
5182 : uint32_t len;
5183 0 : char *newname = NULL;
5184 0 : struct files_struct *dst_dirfsp = NULL;
5185 0 : struct smb_filename *smb_fname_dst = NULL;
5186 0 : const char *dst_original_lcomp = NULL;
5187 0 : NTSTATUS status = NT_STATUS_OK;
5188 : char *p;
5189 0 : TALLOC_CTX *ctx = talloc_tos();
5190 :
5191 0 : if (total_data < 13) {
5192 0 : return NT_STATUS_INVALID_PARAMETER;
5193 : }
5194 :
5195 0 : overwrite = (CVAL(pdata,0) != 0);
5196 0 : root_fid = IVAL(pdata,4);
5197 0 : len = IVAL(pdata,8);
5198 :
5199 0 : if (len > (total_data - 12) || (len == 0) || (root_fid != 0)) {
5200 0 : return NT_STATUS_INVALID_PARAMETER;
5201 : }
5202 :
5203 0 : if (req->posix_pathnames) {
5204 0 : srvstr_get_path_posix(ctx,
5205 : pdata,
5206 0 : req->flags2,
5207 : &newname,
5208 : &pdata[12],
5209 : len,
5210 : 0,
5211 : &status);
5212 : } else {
5213 0 : srvstr_get_path(ctx,
5214 : pdata,
5215 0 : req->flags2,
5216 : &newname,
5217 : &pdata[12],
5218 : len,
5219 : 0,
5220 : &status);
5221 : }
5222 0 : if (!NT_STATUS_IS_OK(status)) {
5223 0 : return status;
5224 : }
5225 :
5226 0 : DEBUG(10,("smb_file_rename_information: got name |%s|\n",
5227 : newname));
5228 :
5229 : /* Check the new name has no '/' characters. */
5230 0 : if (strchr_m(newname, '/')) {
5231 0 : return NT_STATUS_NOT_SUPPORTED;
5232 : }
5233 :
5234 0 : if (fsp && fsp->base_fsp) {
5235 : /* newname must be a stream name. */
5236 0 : if (newname[0] != ':') {
5237 0 : return NT_STATUS_NOT_SUPPORTED;
5238 : }
5239 :
5240 : /* Create an smb_fname to call rename_internals_fsp() with. */
5241 0 : smb_fname_dst = synthetic_smb_fname(talloc_tos(),
5242 0 : fsp->base_fsp->fsp_name->base_name,
5243 : newname,
5244 : NULL,
5245 0 : fsp->base_fsp->fsp_name->twrp,
5246 0 : fsp->base_fsp->fsp_name->flags);
5247 0 : if (smb_fname_dst == NULL) {
5248 0 : status = NT_STATUS_NO_MEMORY;
5249 0 : goto out;
5250 : }
5251 :
5252 : /*
5253 : * Get the original last component, since
5254 : * rename_internals_fsp() requires it.
5255 : */
5256 0 : dst_original_lcomp = get_original_lcomp(smb_fname_dst,
5257 : conn,
5258 : newname,
5259 : 0);
5260 0 : if (dst_original_lcomp == NULL) {
5261 0 : status = NT_STATUS_NO_MEMORY;
5262 0 : goto out;
5263 : }
5264 :
5265 : } else {
5266 : /*
5267 : * Build up an smb_fname_dst based on the filename passed in.
5268 : * We basically just strip off the last component, and put on
5269 : * the newname instead.
5270 : */
5271 0 : char *base_name = NULL;
5272 0 : uint32_t ucf_flags = ucf_flags_from_smb_request(req);
5273 0 : NTTIME dst_twrp = 0;
5274 :
5275 : /* newname must *not* be a stream name. */
5276 0 : if (newname[0] == ':') {
5277 0 : return NT_STATUS_NOT_SUPPORTED;
5278 : }
5279 :
5280 : /*
5281 : * Strip off the last component (filename) of the path passed
5282 : * in.
5283 : */
5284 0 : base_name = talloc_strdup(ctx, smb_fname_src->base_name);
5285 0 : if (!base_name) {
5286 0 : return NT_STATUS_NO_MEMORY;
5287 : }
5288 0 : p = strrchr_m(base_name, '/');
5289 0 : if (p) {
5290 0 : p[1] = '\0';
5291 : } else {
5292 0 : base_name = talloc_strdup(ctx, "");
5293 0 : if (!base_name) {
5294 0 : return NT_STATUS_NO_MEMORY;
5295 : }
5296 : }
5297 : /* Append the new name. */
5298 0 : base_name = talloc_asprintf_append(base_name,
5299 : "%s",
5300 : newname);
5301 0 : if (!base_name) {
5302 0 : return NT_STATUS_NO_MEMORY;
5303 : }
5304 :
5305 0 : if (ucf_flags & UCF_GMT_PATHNAME) {
5306 0 : extract_snapshot_token(base_name, &dst_twrp);
5307 : }
5308 0 : status = filename_convert_dirfsp(ctx,
5309 : conn,
5310 : base_name,
5311 : ucf_flags,
5312 : dst_twrp,
5313 : &dst_dirfsp,
5314 : &smb_fname_dst);
5315 :
5316 0 : if (!NT_STATUS_IS_OK(status)) {
5317 0 : goto out;
5318 : }
5319 0 : dst_original_lcomp = get_original_lcomp(smb_fname_dst,
5320 : conn,
5321 : newname,
5322 : ucf_flags);
5323 0 : if (dst_original_lcomp == NULL) {
5324 0 : status = NT_STATUS_NO_MEMORY;
5325 0 : goto out;
5326 : }
5327 : }
5328 :
5329 0 : if (fsp != NULL && fsp->fsp_flags.is_fsa) {
5330 0 : DEBUG(10,("smb_file_rename_information: "
5331 : "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
5332 : fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
5333 : smb_fname_str_dbg(smb_fname_dst)));
5334 0 : status = rename_internals_fsp(conn,
5335 : fsp,
5336 : dst_dirfsp,
5337 : smb_fname_dst,
5338 : dst_original_lcomp,
5339 : 0,
5340 : overwrite);
5341 : } else {
5342 0 : DEBUG(10,("smb_file_rename_information: "
5343 : "SMB_FILE_RENAME_INFORMATION %s -> %s\n",
5344 : smb_fname_str_dbg(smb_fname_src),
5345 : smb_fname_str_dbg(smb_fname_dst)));
5346 0 : status = rename_internals(ctx,
5347 : conn,
5348 : req,
5349 : NULL, /* src_dirfsp */
5350 : smb_fname_src,
5351 : dst_dirfsp,
5352 : smb_fname_dst,
5353 : dst_original_lcomp,
5354 : 0,
5355 : overwrite,
5356 : FILE_WRITE_ATTRIBUTES);
5357 : }
5358 0 : out:
5359 0 : TALLOC_FREE(smb_fname_dst);
5360 0 : return status;
5361 : }
5362 :
5363 : /****************************************************************************
5364 : Deal with SMB_SET_POSIX_ACL.
5365 : ****************************************************************************/
5366 :
5367 : #if defined(HAVE_POSIX_ACLS)
5368 0 : static NTSTATUS smb_set_posix_acl(connection_struct *conn,
5369 : struct smb_request *req,
5370 : const char *pdata,
5371 : int total_data_in,
5372 : files_struct *fsp,
5373 : struct smb_filename *smb_fname)
5374 : {
5375 : uint16_t posix_acl_version;
5376 : uint16_t num_file_acls;
5377 : uint16_t num_def_acls;
5378 0 : bool valid_file_acls = true;
5379 0 : bool valid_def_acls = true;
5380 : NTSTATUS status;
5381 : unsigned int size_needed;
5382 : unsigned int total_data;
5383 0 : bool close_fsp = false;
5384 :
5385 0 : if (total_data_in < 0) {
5386 0 : status = NT_STATUS_INVALID_PARAMETER;
5387 0 : goto out;
5388 : }
5389 :
5390 0 : total_data = total_data_in;
5391 :
5392 0 : if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
5393 0 : status = NT_STATUS_INVALID_PARAMETER;
5394 0 : goto out;
5395 : }
5396 0 : posix_acl_version = SVAL(pdata,0);
5397 0 : num_file_acls = SVAL(pdata,2);
5398 0 : num_def_acls = SVAL(pdata,4);
5399 :
5400 0 : if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
5401 0 : valid_file_acls = false;
5402 0 : num_file_acls = 0;
5403 : }
5404 :
5405 0 : if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
5406 0 : valid_def_acls = false;
5407 0 : num_def_acls = 0;
5408 : }
5409 :
5410 0 : if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
5411 0 : status = NT_STATUS_INVALID_PARAMETER;
5412 0 : goto out;
5413 : }
5414 :
5415 : /* Wrap checks. */
5416 0 : if (num_file_acls + num_def_acls < num_file_acls) {
5417 0 : status = NT_STATUS_INVALID_PARAMETER;
5418 0 : goto out;
5419 : }
5420 :
5421 0 : size_needed = num_file_acls + num_def_acls;
5422 :
5423 : /*
5424 : * (size_needed * SMB_POSIX_ACL_ENTRY_SIZE) must be less
5425 : * than UINT_MAX, so check by division.
5426 : */
5427 0 : if (size_needed > (UINT_MAX/SMB_POSIX_ACL_ENTRY_SIZE)) {
5428 0 : status = NT_STATUS_INVALID_PARAMETER;
5429 0 : goto out;
5430 : }
5431 :
5432 0 : size_needed = size_needed*SMB_POSIX_ACL_ENTRY_SIZE;
5433 0 : if (size_needed + SMB_POSIX_ACL_HEADER_SIZE < size_needed) {
5434 0 : status = NT_STATUS_INVALID_PARAMETER;
5435 0 : goto out;
5436 : }
5437 0 : size_needed += SMB_POSIX_ACL_HEADER_SIZE;
5438 :
5439 0 : if (total_data < size_needed) {
5440 0 : status = NT_STATUS_INVALID_PARAMETER;
5441 0 : goto out;
5442 : }
5443 :
5444 : /*
5445 : * Ensure we always operate on a file descriptor, not just
5446 : * the filename.
5447 : */
5448 0 : if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
5449 0 : uint32_t access_mask = SEC_STD_WRITE_OWNER|
5450 : SEC_STD_WRITE_DAC|
5451 : SEC_STD_READ_CONTROL|
5452 : FILE_READ_ATTRIBUTES|
5453 : FILE_WRITE_ATTRIBUTES;
5454 :
5455 0 : status = get_posix_fsp(conn,
5456 : req,
5457 : smb_fname,
5458 : access_mask,
5459 : &fsp);
5460 :
5461 0 : if (!NT_STATUS_IS_OK(status)) {
5462 0 : goto out;
5463 : }
5464 0 : close_fsp = true;
5465 : }
5466 :
5467 : /* Here we know fsp != NULL */
5468 0 : SMB_ASSERT(fsp != NULL);
5469 :
5470 0 : status = refuse_symlink_fsp(fsp);
5471 0 : if (!NT_STATUS_IS_OK(status)) {
5472 0 : goto out;
5473 : }
5474 :
5475 : /* If we have a default acl, this *must* be a directory. */
5476 0 : if (valid_def_acls && !fsp->fsp_flags.is_directory) {
5477 0 : DBG_INFO("Can't set default acls on "
5478 : "non-directory %s\n",
5479 : fsp_str_dbg(fsp));
5480 0 : return NT_STATUS_INVALID_HANDLE;
5481 : }
5482 :
5483 0 : DBG_DEBUG("file %s num_file_acls = %"PRIu16", "
5484 : "num_def_acls = %"PRIu16"\n",
5485 : fsp_str_dbg(fsp),
5486 : num_file_acls,
5487 : num_def_acls);
5488 :
5489 : /* Move pdata to the start of the file ACL entries. */
5490 0 : pdata += SMB_POSIX_ACL_HEADER_SIZE;
5491 :
5492 0 : if (valid_file_acls) {
5493 0 : status = set_unix_posix_acl(conn,
5494 : fsp,
5495 : num_file_acls,
5496 : pdata);
5497 0 : if (!NT_STATUS_IS_OK(status)) {
5498 0 : goto out;
5499 : }
5500 : }
5501 :
5502 : /* Move pdata to the start of the default ACL entries. */
5503 0 : pdata += (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE);
5504 :
5505 0 : if (valid_def_acls) {
5506 0 : status = set_unix_posix_default_acl(conn,
5507 : fsp,
5508 : num_def_acls,
5509 : pdata);
5510 0 : if (!NT_STATUS_IS_OK(status)) {
5511 0 : goto out;
5512 : }
5513 : }
5514 :
5515 0 : status = NT_STATUS_OK;
5516 :
5517 0 : out:
5518 :
5519 0 : if (close_fsp) {
5520 0 : (void)close_file_free(req, &fsp, NORMAL_CLOSE);
5521 : }
5522 0 : return status;
5523 : }
5524 : #endif
5525 :
5526 : /****************************************************************************
5527 : Deal with SMB_SET_FILE_BASIC_INFO.
5528 : ****************************************************************************/
5529 :
5530 63 : static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
5531 : const char *pdata,
5532 : int total_data,
5533 : files_struct *fsp,
5534 : struct smb_filename *smb_fname)
5535 : {
5536 : /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
5537 : struct smb_file_time ft;
5538 63 : uint32_t dosmode = 0;
5539 63 : NTSTATUS status = NT_STATUS_OK;
5540 :
5541 63 : init_smb_file_time(&ft);
5542 :
5543 63 : if (total_data < 36) {
5544 0 : return NT_STATUS_INVALID_PARAMETER;
5545 : }
5546 :
5547 63 : if (fsp == NULL) {
5548 0 : return NT_STATUS_INVALID_HANDLE;
5549 : }
5550 :
5551 63 : status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES);
5552 63 : if (!NT_STATUS_IS_OK(status)) {
5553 0 : return status;
5554 : }
5555 :
5556 : /* Set the attributes */
5557 63 : dosmode = IVAL(pdata,32);
5558 63 : status = smb_set_file_dosmode(conn, fsp, dosmode);
5559 63 : if (!NT_STATUS_IS_OK(status)) {
5560 1 : return status;
5561 : }
5562 :
5563 : /* create time */
5564 62 : ft.create_time = pull_long_date_full_timespec(pdata);
5565 :
5566 : /* access time */
5567 62 : ft.atime = pull_long_date_full_timespec(pdata+8);
5568 :
5569 : /* write time. */
5570 62 : ft.mtime = pull_long_date_full_timespec(pdata+16);
5571 :
5572 : /* change time. */
5573 62 : ft.ctime = pull_long_date_full_timespec(pdata+24);
5574 :
5575 62 : DEBUG(10, ("smb_set_file_basic_info: file %s\n",
5576 : smb_fname_str_dbg(smb_fname)));
5577 :
5578 62 : status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
5579 62 : if (!NT_STATUS_IS_OK(status)) {
5580 0 : return status;
5581 : }
5582 :
5583 62 : if (fsp->fsp_flags.modified) {
5584 1 : trigger_write_time_update_immediate(fsp);
5585 : }
5586 62 : return NT_STATUS_OK;
5587 : }
5588 :
5589 : /****************************************************************************
5590 : Deal with SMB_INFO_STANDARD.
5591 : ****************************************************************************/
5592 :
5593 0 : static NTSTATUS smb_set_info_standard(connection_struct *conn,
5594 : const char *pdata,
5595 : int total_data,
5596 : files_struct *fsp,
5597 : struct smb_filename *smb_fname)
5598 : {
5599 : NTSTATUS status;
5600 : struct smb_file_time ft;
5601 :
5602 0 : init_smb_file_time(&ft);
5603 :
5604 0 : if (total_data < 12) {
5605 0 : return NT_STATUS_INVALID_PARAMETER;
5606 : }
5607 :
5608 0 : if (fsp == NULL) {
5609 0 : return NT_STATUS_INVALID_HANDLE;
5610 : }
5611 :
5612 : /* create time */
5613 0 : ft.create_time = time_t_to_full_timespec(srv_make_unix_date2(pdata));
5614 : /* access time */
5615 0 : ft.atime = time_t_to_full_timespec(srv_make_unix_date2(pdata+4));
5616 : /* write time */
5617 0 : ft.mtime = time_t_to_full_timespec(srv_make_unix_date2(pdata+8));
5618 :
5619 0 : DEBUG(10,("smb_set_info_standard: file %s\n",
5620 : smb_fname_str_dbg(smb_fname)));
5621 :
5622 0 : status = check_access_fsp(fsp, FILE_WRITE_ATTRIBUTES);
5623 0 : if (!NT_STATUS_IS_OK(status)) {
5624 0 : return status;
5625 : }
5626 :
5627 0 : status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
5628 0 : if (!NT_STATUS_IS_OK(status)) {
5629 0 : return status;
5630 : }
5631 :
5632 0 : if (fsp->fsp_flags.modified) {
5633 0 : trigger_write_time_update_immediate(fsp);
5634 : }
5635 0 : return NT_STATUS_OK;
5636 : }
5637 :
5638 : /****************************************************************************
5639 : Deal with SMB_SET_FILE_ALLOCATION_INFO.
5640 : ****************************************************************************/
5641 :
5642 0 : static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
5643 : struct smb_request *req,
5644 : const char *pdata,
5645 : int total_data,
5646 : files_struct *fsp,
5647 : struct smb_filename *smb_fname)
5648 : {
5649 0 : uint64_t allocation_size = 0;
5650 0 : NTSTATUS status = NT_STATUS_OK;
5651 0 : files_struct *new_fsp = NULL;
5652 :
5653 0 : if (!VALID_STAT(smb_fname->st)) {
5654 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5655 : }
5656 :
5657 0 : if (total_data < 8) {
5658 0 : return NT_STATUS_INVALID_PARAMETER;
5659 : }
5660 :
5661 0 : allocation_size = (uint64_t)IVAL(pdata,0);
5662 0 : allocation_size |= (((uint64_t)IVAL(pdata,4)) << 32);
5663 0 : DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for "
5664 : "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
5665 : (double)allocation_size));
5666 :
5667 0 : if (allocation_size) {
5668 0 : allocation_size = smb_roundup(conn, allocation_size);
5669 : }
5670 :
5671 0 : DEBUG(10,("smb_set_file_allocation_info: file %s : setting new "
5672 : "allocation size to %.0f\n", smb_fname_str_dbg(smb_fname),
5673 : (double)allocation_size));
5674 :
5675 0 : if (fsp &&
5676 0 : !fsp->fsp_flags.is_pathref &&
5677 0 : fsp_get_io_fd(fsp) != -1)
5678 : {
5679 : /* Open file handle. */
5680 0 : if (!(fsp->access_mask & FILE_WRITE_DATA)) {
5681 0 : return NT_STATUS_ACCESS_DENIED;
5682 : }
5683 :
5684 : /* Only change if needed. */
5685 0 : if (allocation_size != get_file_size_stat(&smb_fname->st)) {
5686 0 : if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
5687 0 : return map_nt_error_from_unix(errno);
5688 : }
5689 : }
5690 : /* But always update the time. */
5691 : /*
5692 : * This is equivalent to a write. Ensure it's seen immediately
5693 : * if there are no pending writes.
5694 : */
5695 0 : trigger_write_time_update_immediate(fsp);
5696 0 : return NT_STATUS_OK;
5697 : }
5698 :
5699 : /* Pathname or stat or directory file. */
5700 0 : status = SMB_VFS_CREATE_FILE(
5701 : conn, /* conn */
5702 : req, /* req */
5703 : NULL, /* dirfsp */
5704 : smb_fname, /* fname */
5705 : FILE_WRITE_DATA, /* access_mask */
5706 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
5707 : FILE_SHARE_DELETE),
5708 : FILE_OPEN, /* create_disposition*/
5709 : 0, /* create_options */
5710 : FILE_ATTRIBUTE_NORMAL, /* file_attributes */
5711 : 0, /* oplock_request */
5712 : NULL, /* lease */
5713 : 0, /* allocation_size */
5714 : 0, /* private_flags */
5715 : NULL, /* sd */
5716 : NULL, /* ea_list */
5717 : &new_fsp, /* result */
5718 : NULL, /* pinfo */
5719 : NULL, NULL); /* create context */
5720 :
5721 0 : if (!NT_STATUS_IS_OK(status)) {
5722 : /* NB. We check for open_was_deferred in the caller. */
5723 0 : return status;
5724 : }
5725 :
5726 : /* Only change if needed. */
5727 0 : if (allocation_size != get_file_size_stat(&smb_fname->st)) {
5728 0 : if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) {
5729 0 : status = map_nt_error_from_unix(errno);
5730 0 : close_file_free(req, &new_fsp, NORMAL_CLOSE);
5731 0 : return status;
5732 : }
5733 : }
5734 :
5735 : /* Changing the allocation size should set the last mod time. */
5736 : /*
5737 : * This is equivalent to a write. Ensure it's seen immediately
5738 : * if there are no pending writes.
5739 : */
5740 0 : trigger_write_time_update_immediate(new_fsp);
5741 0 : close_file_free(req, &new_fsp, NORMAL_CLOSE);
5742 0 : return NT_STATUS_OK;
5743 : }
5744 :
5745 : /****************************************************************************
5746 : Deal with SMB_SET_FILE_END_OF_FILE_INFO.
5747 : ****************************************************************************/
5748 :
5749 0 : static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
5750 : struct smb_request *req,
5751 : const char *pdata,
5752 : int total_data,
5753 : files_struct *fsp,
5754 : struct smb_filename *smb_fname,
5755 : bool fail_after_createfile)
5756 : {
5757 : off_t size;
5758 :
5759 0 : if (total_data < 8) {
5760 0 : return NT_STATUS_INVALID_PARAMETER;
5761 : }
5762 :
5763 0 : size = IVAL(pdata,0);
5764 0 : size |= (((off_t)IVAL(pdata,4)) << 32);
5765 0 : DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for "
5766 : "file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
5767 : (double)size));
5768 :
5769 0 : return smb_set_file_size(conn, req,
5770 : fsp,
5771 : smb_fname,
5772 0 : &smb_fname->st,
5773 : size,
5774 : fail_after_createfile);
5775 : }
5776 :
5777 : /****************************************************************************
5778 : Allow a UNIX info mknod.
5779 : ****************************************************************************/
5780 :
5781 0 : static NTSTATUS smb_unix_mknod(connection_struct *conn,
5782 : const char *pdata,
5783 : int total_data,
5784 : const struct smb_filename *smb_fname)
5785 : {
5786 0 : uint32_t file_type = IVAL(pdata,56);
5787 : #if defined(HAVE_MAKEDEV)
5788 0 : uint32_t dev_major = IVAL(pdata,60);
5789 0 : uint32_t dev_minor = IVAL(pdata,68);
5790 : #endif
5791 0 : SMB_DEV_T dev = (SMB_DEV_T)0;
5792 0 : uint32_t raw_unixmode = IVAL(pdata,84);
5793 : NTSTATUS status;
5794 : mode_t unixmode;
5795 : int ret;
5796 0 : struct smb_filename *parent_fname = NULL;
5797 0 : struct smb_filename *base_name = NULL;
5798 :
5799 0 : if (total_data < 100) {
5800 0 : return NT_STATUS_INVALID_PARAMETER;
5801 : }
5802 :
5803 0 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
5804 : PERM_NEW_FILE, &unixmode);
5805 0 : if (!NT_STATUS_IS_OK(status)) {
5806 0 : return status;
5807 : }
5808 :
5809 : #if defined(HAVE_MAKEDEV)
5810 0 : dev = makedev(dev_major, dev_minor);
5811 : #endif
5812 :
5813 0 : switch (file_type) {
5814 : /* We can't create other objects here. */
5815 0 : case UNIX_TYPE_FILE:
5816 : case UNIX_TYPE_DIR:
5817 : case UNIX_TYPE_SYMLINK:
5818 0 : return NT_STATUS_ACCESS_DENIED;
5819 : #if defined(S_IFIFO)
5820 0 : case UNIX_TYPE_FIFO:
5821 0 : unixmode |= S_IFIFO;
5822 0 : break;
5823 : #endif
5824 : #if defined(S_IFSOCK)
5825 0 : case UNIX_TYPE_SOCKET:
5826 0 : unixmode |= S_IFSOCK;
5827 0 : break;
5828 : #endif
5829 : #if defined(S_IFCHR)
5830 0 : case UNIX_TYPE_CHARDEV:
5831 : /* This is only allowed for root. */
5832 0 : if (get_current_uid(conn) != sec_initial_uid()) {
5833 0 : return NT_STATUS_ACCESS_DENIED;
5834 : }
5835 0 : unixmode |= S_IFCHR;
5836 0 : break;
5837 : #endif
5838 : #if defined(S_IFBLK)
5839 0 : case UNIX_TYPE_BLKDEV:
5840 0 : if (get_current_uid(conn) != sec_initial_uid()) {
5841 0 : return NT_STATUS_ACCESS_DENIED;
5842 : }
5843 0 : unixmode |= S_IFBLK;
5844 0 : break;
5845 : #endif
5846 0 : default:
5847 0 : return NT_STATUS_INVALID_PARAMETER;
5848 : }
5849 :
5850 0 : DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev "
5851 : "%.0f mode 0%o for file %s\n", (double)dev,
5852 : (unsigned int)unixmode, smb_fname_str_dbg(smb_fname)));
5853 :
5854 0 : status = parent_pathref(talloc_tos(),
5855 : conn->cwd_fsp,
5856 : smb_fname,
5857 : &parent_fname,
5858 : &base_name);
5859 0 : if (!NT_STATUS_IS_OK(status)) {
5860 0 : return status;
5861 : }
5862 :
5863 : /* Ok - do the mknod. */
5864 0 : ret = SMB_VFS_MKNODAT(conn,
5865 : parent_fname->fsp,
5866 : base_name,
5867 : unixmode,
5868 : dev);
5869 :
5870 0 : if (ret != 0) {
5871 0 : TALLOC_FREE(parent_fname);
5872 0 : return map_nt_error_from_unix(errno);
5873 : }
5874 :
5875 : /* If any of the other "set" calls fail we
5876 : * don't want to end up with a half-constructed mknod.
5877 : */
5878 :
5879 0 : if (lp_inherit_permissions(SNUM(conn))) {
5880 0 : inherit_access_posix_acl(conn,
5881 0 : parent_fname->fsp,
5882 : smb_fname,
5883 : unixmode);
5884 : }
5885 0 : TALLOC_FREE(parent_fname);
5886 :
5887 0 : return NT_STATUS_OK;
5888 : }
5889 :
5890 : /****************************************************************************
5891 : Deal with SMB_SET_FILE_UNIX_BASIC.
5892 : ****************************************************************************/
5893 :
5894 0 : static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
5895 : struct smb_request *req,
5896 : const char *pdata,
5897 : int total_data,
5898 : files_struct *fsp,
5899 : struct smb_filename *smb_fname)
5900 : {
5901 : struct smb_file_time ft;
5902 : uint32_t raw_unixmode;
5903 : mode_t unixmode;
5904 0 : off_t size = 0;
5905 0 : uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
5906 0 : gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
5907 0 : NTSTATUS status = NT_STATUS_OK;
5908 : enum perm_type ptype;
5909 0 : files_struct *all_fsps = NULL;
5910 0 : bool modify_mtime = true;
5911 : struct file_id id;
5912 : SMB_STRUCT_STAT sbuf;
5913 :
5914 0 : init_smb_file_time(&ft);
5915 :
5916 0 : if (total_data < 100) {
5917 0 : return NT_STATUS_INVALID_PARAMETER;
5918 : }
5919 :
5920 0 : if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
5921 0 : IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
5922 0 : size=IVAL(pdata,0); /* first 8 Bytes are size */
5923 0 : size |= (((off_t)IVAL(pdata,4)) << 32);
5924 : }
5925 :
5926 0 : ft.atime = pull_long_date_full_timespec(pdata+24); /* access_time */
5927 0 : ft.mtime = pull_long_date_full_timespec(pdata+32); /* modification_time */
5928 0 : set_owner = (uid_t)IVAL(pdata,40);
5929 0 : set_grp = (gid_t)IVAL(pdata,48);
5930 0 : raw_unixmode = IVAL(pdata,84);
5931 :
5932 0 : if (VALID_STAT(smb_fname->st)) {
5933 0 : if (S_ISDIR(smb_fname->st.st_ex_mode)) {
5934 0 : ptype = PERM_EXISTING_DIR;
5935 : } else {
5936 0 : ptype = PERM_EXISTING_FILE;
5937 : }
5938 : } else {
5939 0 : ptype = PERM_NEW_FILE;
5940 : }
5941 :
5942 0 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
5943 : ptype, &unixmode);
5944 0 : if (!NT_STATUS_IS_OK(status)) {
5945 0 : return status;
5946 : }
5947 :
5948 0 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = "
5949 : "%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
5950 : smb_fname_str_dbg(smb_fname), (double)size,
5951 : (unsigned int)set_owner, (unsigned int)set_grp,
5952 : (int)raw_unixmode));
5953 :
5954 0 : sbuf = smb_fname->st;
5955 :
5956 0 : if (!VALID_STAT(sbuf)) {
5957 : /*
5958 : * The only valid use of this is to create character and block
5959 : * devices, and named pipes. This is deprecated (IMHO) and
5960 : * a new info level should be used for mknod. JRA.
5961 : */
5962 :
5963 0 : return smb_unix_mknod(conn,
5964 : pdata,
5965 : total_data,
5966 : smb_fname);
5967 : }
5968 :
5969 : #if 1
5970 : /* Horrible backwards compatibility hack as an old server bug
5971 : * allowed a CIFS client bug to remain unnoticed :-(. JRA.
5972 : * */
5973 :
5974 0 : if (!size) {
5975 0 : size = get_file_size_stat(&sbuf);
5976 : }
5977 : #endif
5978 :
5979 : /*
5980 : * Deal with the UNIX specific mode set.
5981 : */
5982 :
5983 0 : if (raw_unixmode != SMB_MODE_NO_CHANGE) {
5984 : int ret;
5985 :
5986 0 : if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
5987 0 : DBG_WARNING("Can't set mode on symlink %s\n",
5988 : smb_fname_str_dbg(smb_fname));
5989 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
5990 : }
5991 :
5992 0 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
5993 : "setting mode 0%o for file %s\n",
5994 : (unsigned int)unixmode,
5995 : smb_fname_str_dbg(smb_fname)));
5996 0 : ret = SMB_VFS_FCHMOD(fsp, unixmode);
5997 0 : if (ret != 0) {
5998 0 : return map_nt_error_from_unix(errno);
5999 : }
6000 : }
6001 :
6002 : /*
6003 : * Deal with the UNIX specific uid set.
6004 : */
6005 :
6006 0 : if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) &&
6007 0 : (sbuf.st_ex_uid != set_owner)) {
6008 : int ret;
6009 :
6010 0 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6011 : "changing owner %u for path %s\n",
6012 : (unsigned int)set_owner,
6013 : smb_fname_str_dbg(smb_fname)));
6014 :
6015 0 : if (fsp &&
6016 0 : !fsp->fsp_flags.is_pathref &&
6017 0 : fsp_get_io_fd(fsp) != -1)
6018 : {
6019 0 : ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
6020 : } else {
6021 : /*
6022 : * UNIX extensions calls must always operate
6023 : * on symlinks.
6024 : */
6025 0 : ret = SMB_VFS_LCHOWN(conn, smb_fname,
6026 : set_owner, (gid_t)-1);
6027 : }
6028 :
6029 0 : if (ret != 0) {
6030 0 : status = map_nt_error_from_unix(errno);
6031 0 : return status;
6032 : }
6033 : }
6034 :
6035 : /*
6036 : * Deal with the UNIX specific gid set.
6037 : */
6038 :
6039 0 : if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
6040 0 : (sbuf.st_ex_gid != set_grp)) {
6041 : int ret;
6042 :
6043 0 : DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
6044 : "changing group %u for file %s\n",
6045 : (unsigned int)set_grp,
6046 : smb_fname_str_dbg(smb_fname)));
6047 0 : if (fsp &&
6048 0 : !fsp->fsp_flags.is_pathref &&
6049 0 : fsp_get_io_fd(fsp) != -1)
6050 : {
6051 0 : ret = SMB_VFS_FCHOWN(fsp, (uid_t)-1, set_grp);
6052 : } else {
6053 : /*
6054 : * UNIX extensions calls must always operate
6055 : * on symlinks.
6056 : */
6057 0 : ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
6058 : set_grp);
6059 : }
6060 0 : if (ret != 0) {
6061 0 : status = map_nt_error_from_unix(errno);
6062 0 : return status;
6063 : }
6064 : }
6065 :
6066 : /* Deal with any size changes. */
6067 :
6068 0 : if (S_ISREG(sbuf.st_ex_mode)) {
6069 0 : status = smb_set_file_size(conn, req,
6070 : fsp,
6071 : smb_fname,
6072 : &sbuf,
6073 : size,
6074 : false);
6075 0 : if (!NT_STATUS_IS_OK(status)) {
6076 0 : return status;
6077 : }
6078 : }
6079 :
6080 : /* Deal with any time changes. */
6081 0 : if (is_omit_timespec(&ft.mtime) && is_omit_timespec(&ft.atime)) {
6082 : /* No change, don't cancel anything. */
6083 0 : return status;
6084 : }
6085 :
6086 0 : id = vfs_file_id_from_sbuf(conn, &sbuf);
6087 0 : for(all_fsps = file_find_di_first(conn->sconn, id, true); all_fsps;
6088 0 : all_fsps = file_find_di_next(all_fsps, true)) {
6089 : /*
6090 : * We're setting the time explicitly for UNIX.
6091 : * Cancel any pending changes over all handles.
6092 : */
6093 0 : all_fsps->fsp_flags.update_write_time_on_close = false;
6094 0 : TALLOC_FREE(all_fsps->update_write_time_event);
6095 : }
6096 :
6097 : /*
6098 : * Override the "setting_write_time"
6099 : * parameter here as it almost does what
6100 : * we need. Just remember if we modified
6101 : * mtime and send the notify ourselves.
6102 : */
6103 0 : if (is_omit_timespec(&ft.mtime)) {
6104 0 : modify_mtime = false;
6105 : }
6106 :
6107 0 : status = smb_set_file_time(conn,
6108 : fsp,
6109 : smb_fname,
6110 : &ft,
6111 : false);
6112 0 : if (modify_mtime) {
6113 0 : notify_fname(conn, NOTIFY_ACTION_MODIFIED,
6114 0 : FILE_NOTIFY_CHANGE_LAST_WRITE, smb_fname->base_name);
6115 : }
6116 0 : return status;
6117 : }
6118 :
6119 : /****************************************************************************
6120 : Deal with SMB_SET_FILE_UNIX_INFO2.
6121 : ****************************************************************************/
6122 :
6123 0 : static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
6124 : struct smb_request *req,
6125 : const char *pdata,
6126 : int total_data,
6127 : files_struct *fsp,
6128 : struct smb_filename *smb_fname)
6129 : {
6130 : NTSTATUS status;
6131 : uint32_t smb_fflags;
6132 : uint32_t smb_fmask;
6133 :
6134 0 : if (total_data < 116) {
6135 0 : return NT_STATUS_INVALID_PARAMETER;
6136 : }
6137 :
6138 : /* Start by setting all the fields that are common between UNIX_BASIC
6139 : * and UNIX_INFO2.
6140 : */
6141 0 : status = smb_set_file_unix_basic(conn, req, pdata, total_data,
6142 : fsp, smb_fname);
6143 0 : if (!NT_STATUS_IS_OK(status)) {
6144 0 : return status;
6145 : }
6146 :
6147 0 : smb_fflags = IVAL(pdata, 108);
6148 0 : smb_fmask = IVAL(pdata, 112);
6149 :
6150 : /* NB: We should only attempt to alter the file flags if the client
6151 : * sends a non-zero mask.
6152 : */
6153 0 : if (smb_fmask != 0) {
6154 0 : int stat_fflags = 0;
6155 :
6156 0 : if (!map_info2_flags_to_sbuf(&smb_fname->st, smb_fflags,
6157 : smb_fmask, &stat_fflags)) {
6158 : /* Client asked to alter a flag we don't understand. */
6159 0 : return NT_STATUS_INVALID_PARAMETER;
6160 : }
6161 :
6162 0 : if (fsp == NULL || S_ISLNK(smb_fname->st.st_ex_mode)) {
6163 0 : DBG_WARNING("Can't change flags on symlink %s\n",
6164 : smb_fname_str_dbg(smb_fname));
6165 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6166 : }
6167 0 : if (SMB_VFS_FCHFLAGS(fsp, stat_fflags) != 0) {
6168 0 : return map_nt_error_from_unix(errno);
6169 : }
6170 : }
6171 :
6172 : /* XXX: need to add support for changing the create_time here. You
6173 : * can do this for paths on Darwin with setattrlist(2). The right way
6174 : * to hook this up is probably by extending the VFS utimes interface.
6175 : */
6176 :
6177 0 : return NT_STATUS_OK;
6178 : }
6179 :
6180 : /****************************************************************************
6181 : Create a directory with POSIX semantics.
6182 : ****************************************************************************/
6183 :
6184 0 : static NTSTATUS smb_posix_mkdir(connection_struct *conn,
6185 : struct smb_request *req,
6186 : char **ppdata,
6187 : int total_data,
6188 : struct smb_filename *smb_fname,
6189 : int *pdata_return_size)
6190 : {
6191 0 : NTSTATUS status = NT_STATUS_OK;
6192 0 : uint32_t raw_unixmode = 0;
6193 0 : mode_t unixmode = (mode_t)0;
6194 0 : files_struct *fsp = NULL;
6195 0 : uint16_t info_level_return = 0;
6196 : int info;
6197 0 : char *pdata = *ppdata;
6198 0 : struct smb2_create_blobs *posx = NULL;
6199 :
6200 0 : if (total_data < 18) {
6201 0 : return NT_STATUS_INVALID_PARAMETER;
6202 : }
6203 :
6204 0 : raw_unixmode = IVAL(pdata,8);
6205 : /* Next 4 bytes are not yet defined. */
6206 :
6207 0 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6208 : PERM_NEW_DIR, &unixmode);
6209 0 : if (!NT_STATUS_IS_OK(status)) {
6210 0 : return status;
6211 : }
6212 :
6213 0 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
6214 0 : if (!NT_STATUS_IS_OK(status)) {
6215 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
6216 : nt_errstr(status));
6217 0 : return status;
6218 : }
6219 :
6220 0 : DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
6221 : smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
6222 :
6223 0 : status = SMB_VFS_CREATE_FILE(
6224 : conn, /* conn */
6225 : req, /* req */
6226 : NULL, /* dirfsp */
6227 : smb_fname, /* fname */
6228 : FILE_READ_ATTRIBUTES, /* access_mask */
6229 : FILE_SHARE_NONE, /* share_access */
6230 : FILE_CREATE, /* create_disposition*/
6231 : FILE_DIRECTORY_FILE, /* create_options */
6232 : 0, /* file_attributes */
6233 : 0, /* oplock_request */
6234 : NULL, /* lease */
6235 : 0, /* allocation_size */
6236 : 0, /* private_flags */
6237 : NULL, /* sd */
6238 : NULL, /* ea_list */
6239 : &fsp, /* result */
6240 : &info, /* pinfo */
6241 : posx, /* in_context_blobs */
6242 : NULL); /* out_context_blobs */
6243 :
6244 0 : TALLOC_FREE(posx);
6245 :
6246 0 : if (NT_STATUS_IS_OK(status)) {
6247 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
6248 : }
6249 :
6250 0 : info_level_return = SVAL(pdata,16);
6251 :
6252 0 : if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
6253 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
6254 0 : } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
6255 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
6256 : } else {
6257 0 : *pdata_return_size = 12;
6258 : }
6259 :
6260 : /* Realloc the data size */
6261 0 : *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
6262 0 : if (*ppdata == NULL) {
6263 0 : *pdata_return_size = 0;
6264 0 : return NT_STATUS_NO_MEMORY;
6265 : }
6266 0 : pdata = *ppdata;
6267 :
6268 0 : SSVAL(pdata,0,NO_OPLOCK_RETURN);
6269 0 : SSVAL(pdata,2,0); /* No fnum. */
6270 0 : SIVAL(pdata,4,info); /* Was directory created. */
6271 :
6272 0 : switch (info_level_return) {
6273 0 : case SMB_QUERY_FILE_UNIX_BASIC:
6274 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
6275 0 : SSVAL(pdata,10,0); /* Padding. */
6276 0 : store_file_unix_basic(conn, pdata + 12, fsp,
6277 0 : &smb_fname->st);
6278 0 : break;
6279 0 : case SMB_QUERY_FILE_UNIX_INFO2:
6280 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
6281 0 : SSVAL(pdata,10,0); /* Padding. */
6282 0 : store_file_unix_basic_info2(conn, pdata + 12, fsp,
6283 0 : &smb_fname->st);
6284 0 : break;
6285 0 : default:
6286 0 : SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
6287 0 : SSVAL(pdata,10,0); /* Padding. */
6288 0 : break;
6289 : }
6290 :
6291 0 : return status;
6292 : }
6293 :
6294 : /****************************************************************************
6295 : Open/Create a file with POSIX semantics.
6296 : ****************************************************************************/
6297 :
6298 : #define SMB_O_RDONLY_MAPPING (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
6299 : #define SMB_O_WRONLY_MAPPING (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA)
6300 :
6301 0 : static NTSTATUS smb_posix_open(connection_struct *conn,
6302 : struct smb_request *req,
6303 : char **ppdata,
6304 : int total_data,
6305 : struct smb_filename *smb_fname,
6306 : int *pdata_return_size)
6307 : {
6308 0 : bool extended_oplock_granted = False;
6309 0 : char *pdata = *ppdata;
6310 0 : uint32_t flags = 0;
6311 0 : uint32_t wire_open_mode = 0;
6312 0 : uint32_t raw_unixmode = 0;
6313 0 : uint32_t attributes = 0;
6314 0 : uint32_t create_disp = 0;
6315 0 : uint32_t access_mask = 0;
6316 0 : uint32_t create_options = FILE_NON_DIRECTORY_FILE;
6317 0 : NTSTATUS status = NT_STATUS_OK;
6318 0 : mode_t unixmode = (mode_t)0;
6319 0 : files_struct *fsp = NULL;
6320 0 : int oplock_request = 0;
6321 0 : int info = 0;
6322 0 : uint16_t info_level_return = 0;
6323 0 : struct smb2_create_blobs *posx = NULL;
6324 :
6325 0 : if (total_data < 18) {
6326 0 : return NT_STATUS_INVALID_PARAMETER;
6327 : }
6328 :
6329 0 : flags = IVAL(pdata,0);
6330 0 : oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
6331 0 : if (oplock_request) {
6332 0 : oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
6333 : }
6334 :
6335 0 : wire_open_mode = IVAL(pdata,4);
6336 :
6337 0 : if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
6338 0 : return smb_posix_mkdir(conn, req,
6339 : ppdata,
6340 : total_data,
6341 : smb_fname,
6342 : pdata_return_size);
6343 : }
6344 :
6345 0 : switch (wire_open_mode & SMB_ACCMODE) {
6346 0 : case SMB_O_RDONLY:
6347 0 : access_mask = SMB_O_RDONLY_MAPPING;
6348 0 : break;
6349 0 : case SMB_O_WRONLY:
6350 0 : access_mask = SMB_O_WRONLY_MAPPING;
6351 0 : break;
6352 0 : case SMB_O_RDWR:
6353 0 : access_mask = (SMB_O_RDONLY_MAPPING|
6354 : SMB_O_WRONLY_MAPPING);
6355 0 : break;
6356 0 : default:
6357 0 : DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
6358 : (unsigned int)wire_open_mode ));
6359 0 : return NT_STATUS_INVALID_PARAMETER;
6360 : }
6361 :
6362 0 : wire_open_mode &= ~SMB_ACCMODE;
6363 :
6364 : /* First take care of O_CREAT|O_EXCL interactions. */
6365 0 : switch (wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) {
6366 0 : case (SMB_O_CREAT | SMB_O_EXCL):
6367 : /* File exists fail. File not exist create. */
6368 0 : create_disp = FILE_CREATE;
6369 0 : break;
6370 0 : case SMB_O_CREAT:
6371 : /* File exists open. File not exist create. */
6372 0 : create_disp = FILE_OPEN_IF;
6373 0 : break;
6374 0 : case SMB_O_EXCL:
6375 : /* O_EXCL on its own without O_CREAT is undefined.
6376 : We deliberately ignore it as some versions of
6377 : Linux CIFSFS can send a bare O_EXCL on the
6378 : wire which other filesystems in the kernel
6379 : ignore. See bug 9519 for details. */
6380 :
6381 : /* Fallthrough. */
6382 :
6383 : case 0:
6384 : /* File exists open. File not exist fail. */
6385 0 : create_disp = FILE_OPEN;
6386 0 : break;
6387 0 : default:
6388 0 : DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
6389 : (unsigned int)wire_open_mode ));
6390 0 : return NT_STATUS_INVALID_PARAMETER;
6391 : }
6392 :
6393 : /* Next factor in the effects of O_TRUNC. */
6394 0 : wire_open_mode &= ~(SMB_O_CREAT | SMB_O_EXCL);
6395 :
6396 0 : if (wire_open_mode & SMB_O_TRUNC) {
6397 0 : switch (create_disp) {
6398 0 : case FILE_CREATE:
6399 : /* (SMB_O_CREAT | SMB_O_EXCL | O_TRUNC) */
6400 : /* Leave create_disp alone as
6401 : (O_CREAT|O_EXCL|O_TRUNC) == (O_CREAT|O_EXCL)
6402 : */
6403 : /* File exists fail. File not exist create. */
6404 0 : break;
6405 0 : case FILE_OPEN_IF:
6406 : /* SMB_O_CREAT | SMB_O_TRUNC */
6407 : /* File exists overwrite. File not exist create. */
6408 0 : create_disp = FILE_OVERWRITE_IF;
6409 0 : break;
6410 0 : case FILE_OPEN:
6411 : /* SMB_O_TRUNC */
6412 : /* File exists overwrite. File not exist fail. */
6413 0 : create_disp = FILE_OVERWRITE;
6414 0 : break;
6415 0 : default:
6416 : /* Cannot get here. */
6417 0 : smb_panic("smb_posix_open: logic error");
6418 : return NT_STATUS_INVALID_PARAMETER;
6419 : }
6420 0 : }
6421 :
6422 0 : raw_unixmode = IVAL(pdata,8);
6423 : /* Next 4 bytes are not yet defined. */
6424 :
6425 0 : status = unix_perms_from_wire(conn, &smb_fname->st, raw_unixmode,
6426 0 : (VALID_STAT(smb_fname->st) ?
6427 : PERM_EXISTING_FILE : PERM_NEW_FILE),
6428 : &unixmode);
6429 :
6430 0 : if (!NT_STATUS_IS_OK(status)) {
6431 0 : return status;
6432 : }
6433 :
6434 0 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
6435 0 : if (!NT_STATUS_IS_OK(status)) {
6436 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
6437 : nt_errstr(status));
6438 0 : return status;
6439 : }
6440 :
6441 0 : if (wire_open_mode & SMB_O_SYNC) {
6442 0 : create_options |= FILE_WRITE_THROUGH;
6443 : }
6444 0 : if (wire_open_mode & SMB_O_APPEND) {
6445 0 : access_mask |= FILE_APPEND_DATA;
6446 : }
6447 0 : if (wire_open_mode & SMB_O_DIRECT) {
6448 0 : attributes |= FILE_FLAG_NO_BUFFERING;
6449 : }
6450 :
6451 0 : if ((wire_open_mode & SMB_O_DIRECTORY) ||
6452 0 : VALID_STAT_OF_DIR(smb_fname->st)) {
6453 0 : if (access_mask != SMB_O_RDONLY_MAPPING) {
6454 0 : return NT_STATUS_FILE_IS_A_DIRECTORY;
6455 : }
6456 0 : create_options &= ~FILE_NON_DIRECTORY_FILE;
6457 0 : create_options |= FILE_DIRECTORY_FILE;
6458 : }
6459 :
6460 0 : DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
6461 : smb_fname_str_dbg(smb_fname),
6462 : (unsigned int)wire_open_mode,
6463 : (unsigned int)unixmode ));
6464 :
6465 0 : status = SMB_VFS_CREATE_FILE(
6466 : conn, /* conn */
6467 : req, /* req */
6468 : NULL, /* dirfsp */
6469 : smb_fname, /* fname */
6470 : access_mask, /* access_mask */
6471 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6472 : FILE_SHARE_DELETE),
6473 : create_disp, /* create_disposition*/
6474 : create_options, /* create_options */
6475 : attributes, /* file_attributes */
6476 : oplock_request, /* oplock_request */
6477 : NULL, /* lease */
6478 : 0, /* allocation_size */
6479 : 0, /* private_flags */
6480 : NULL, /* sd */
6481 : NULL, /* ea_list */
6482 : &fsp, /* result */
6483 : &info, /* pinfo */
6484 : posx, /* in_context_blobs */
6485 : NULL); /* out_context_blobs */
6486 :
6487 0 : TALLOC_FREE(posx);
6488 :
6489 0 : if (!NT_STATUS_IS_OK(status)) {
6490 0 : return status;
6491 : }
6492 :
6493 0 : if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
6494 0 : extended_oplock_granted = True;
6495 : }
6496 :
6497 0 : if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
6498 0 : extended_oplock_granted = True;
6499 : }
6500 :
6501 0 : info_level_return = SVAL(pdata,16);
6502 :
6503 : /* Allocate the correct return size. */
6504 :
6505 0 : if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
6506 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
6507 0 : } else if (info_level_return == SMB_QUERY_FILE_UNIX_INFO2) {
6508 0 : *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
6509 : } else {
6510 0 : *pdata_return_size = 12;
6511 : }
6512 :
6513 : /* Realloc the data size */
6514 0 : *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
6515 0 : if (*ppdata == NULL) {
6516 0 : close_file_free(req, &fsp, ERROR_CLOSE);
6517 0 : *pdata_return_size = 0;
6518 0 : return NT_STATUS_NO_MEMORY;
6519 : }
6520 0 : pdata = *ppdata;
6521 :
6522 0 : if (extended_oplock_granted) {
6523 0 : if (flags & REQUEST_BATCH_OPLOCK) {
6524 0 : SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
6525 : } else {
6526 0 : SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
6527 : }
6528 0 : } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
6529 0 : SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
6530 : } else {
6531 0 : SSVAL(pdata,0,NO_OPLOCK_RETURN);
6532 : }
6533 :
6534 0 : SSVAL(pdata,2,fsp->fnum);
6535 0 : SIVAL(pdata,4,info); /* Was file created etc. */
6536 :
6537 0 : switch (info_level_return) {
6538 0 : case SMB_QUERY_FILE_UNIX_BASIC:
6539 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
6540 0 : SSVAL(pdata,10,0); /* padding. */
6541 0 : store_file_unix_basic(conn, pdata + 12, fsp,
6542 0 : &smb_fname->st);
6543 0 : break;
6544 0 : case SMB_QUERY_FILE_UNIX_INFO2:
6545 0 : SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
6546 0 : SSVAL(pdata,10,0); /* padding. */
6547 0 : store_file_unix_basic_info2(conn, pdata + 12, fsp,
6548 0 : &smb_fname->st);
6549 0 : break;
6550 0 : default:
6551 0 : SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
6552 0 : SSVAL(pdata,10,0); /* padding. */
6553 0 : break;
6554 : }
6555 0 : return NT_STATUS_OK;
6556 : }
6557 :
6558 : /****************************************************************************
6559 : Delete a file with POSIX semantics.
6560 : ****************************************************************************/
6561 :
6562 0 : static NTSTATUS smb_posix_unlink(connection_struct *conn,
6563 : struct smb_request *req,
6564 : const char *pdata,
6565 : int total_data,
6566 : struct smb_filename *smb_fname)
6567 : {
6568 0 : NTSTATUS status = NT_STATUS_OK;
6569 0 : files_struct *fsp = NULL;
6570 0 : uint16_t flags = 0;
6571 0 : char del = 1;
6572 0 : int info = 0;
6573 0 : int create_options = 0;
6574 0 : struct share_mode_lock *lck = NULL;
6575 : bool other_nonposix_opens;
6576 0 : struct smb2_create_blobs *posx = NULL;
6577 :
6578 0 : if (total_data < 2) {
6579 0 : return NT_STATUS_INVALID_PARAMETER;
6580 : }
6581 :
6582 0 : flags = SVAL(pdata,0);
6583 :
6584 0 : if (!VALID_STAT(smb_fname->st)) {
6585 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6586 : }
6587 :
6588 0 : if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
6589 0 : !VALID_STAT_OF_DIR(smb_fname->st)) {
6590 0 : return NT_STATUS_NOT_A_DIRECTORY;
6591 : }
6592 :
6593 0 : DEBUG(10,("smb_posix_unlink: %s %s\n",
6594 : (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
6595 : smb_fname_str_dbg(smb_fname)));
6596 :
6597 0 : if (VALID_STAT_OF_DIR(smb_fname->st)) {
6598 0 : create_options |= FILE_DIRECTORY_FILE;
6599 : }
6600 :
6601 0 : status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
6602 0 : if (!NT_STATUS_IS_OK(status)) {
6603 0 : DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
6604 : nt_errstr(status));
6605 0 : return status;
6606 : }
6607 :
6608 0 : status = SMB_VFS_CREATE_FILE(
6609 : conn, /* conn */
6610 : req, /* req */
6611 : NULL, /* dirfsp */
6612 : smb_fname, /* fname */
6613 : DELETE_ACCESS, /* access_mask */
6614 : (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
6615 : FILE_SHARE_DELETE),
6616 : FILE_OPEN, /* create_disposition*/
6617 : create_options, /* create_options */
6618 : 0, /* file_attributes */
6619 : 0, /* oplock_request */
6620 : NULL, /* lease */
6621 : 0, /* allocation_size */
6622 : 0, /* private_flags */
6623 : NULL, /* sd */
6624 : NULL, /* ea_list */
6625 : &fsp, /* result */
6626 : &info, /* pinfo */
6627 : posx, /* in_context_blobs */
6628 : NULL); /* out_context_blobs */
6629 :
6630 0 : TALLOC_FREE(posx);
6631 :
6632 0 : if (!NT_STATUS_IS_OK(status)) {
6633 0 : return status;
6634 : }
6635 :
6636 : /*
6637 : * Don't lie to client. If we can't really delete due to
6638 : * non-POSIX opens return SHARING_VIOLATION.
6639 : */
6640 :
6641 0 : lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
6642 0 : if (lck == NULL) {
6643 0 : DEBUG(0, ("smb_posix_unlink: Could not get share mode "
6644 : "lock for file %s\n", fsp_str_dbg(fsp)));
6645 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
6646 0 : return NT_STATUS_INVALID_PARAMETER;
6647 : }
6648 :
6649 0 : other_nonposix_opens = has_other_nonposix_opens(lck, fsp);
6650 0 : if (other_nonposix_opens) {
6651 : /* Fail with sharing violation. */
6652 0 : TALLOC_FREE(lck);
6653 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
6654 0 : return NT_STATUS_SHARING_VIOLATION;
6655 : }
6656 :
6657 : /*
6658 : * Set the delete on close.
6659 : */
6660 0 : status = smb_set_file_disposition_info(conn,
6661 : &del,
6662 : 1,
6663 : fsp,
6664 : smb_fname);
6665 :
6666 0 : TALLOC_FREE(lck);
6667 :
6668 0 : if (!NT_STATUS_IS_OK(status)) {
6669 0 : close_file_free(req, &fsp, NORMAL_CLOSE);
6670 0 : return status;
6671 : }
6672 0 : return close_file_free(req, &fsp, NORMAL_CLOSE);
6673 : }
6674 :
6675 0 : static NTSTATUS smbd_do_posix_setfilepathinfo(struct connection_struct *conn,
6676 : struct smb_request *req,
6677 : TALLOC_CTX *mem_ctx,
6678 : uint16_t info_level,
6679 : struct smb_filename *smb_fname,
6680 : files_struct *fsp,
6681 : char **ppdata,
6682 : int total_data,
6683 : int *ret_data_size)
6684 : {
6685 0 : char *pdata = *ppdata;
6686 0 : NTSTATUS status = NT_STATUS_OK;
6687 0 : int data_return_size = 0;
6688 :
6689 0 : *ret_data_size = 0;
6690 :
6691 0 : if (!CAN_WRITE(conn)) {
6692 : /* Allow POSIX opens. The open path will deny
6693 : * any non-readonly opens. */
6694 0 : if (info_level != SMB_POSIX_PATH_OPEN) {
6695 0 : return NT_STATUS_DOS(ERRSRV, ERRaccess);
6696 : }
6697 : }
6698 :
6699 0 : DBG_DEBUG("file=%s (%s) info_level=%d totdata=%d\n",
6700 : smb_fname_str_dbg(smb_fname),
6701 : fsp_fnum_dbg(fsp),
6702 : info_level,
6703 : total_data);
6704 :
6705 0 : switch (info_level) {
6706 0 : case SMB_SET_FILE_UNIX_BASIC:
6707 : {
6708 0 : status = smb_set_file_unix_basic(conn, req,
6709 : pdata,
6710 : total_data,
6711 : fsp,
6712 : smb_fname);
6713 0 : break;
6714 : }
6715 :
6716 0 : case SMB_SET_FILE_UNIX_INFO2:
6717 : {
6718 0 : status = smb_set_file_unix_info2(conn, req,
6719 : pdata,
6720 : total_data,
6721 : fsp,
6722 : smb_fname);
6723 0 : break;
6724 : }
6725 :
6726 0 : case SMB_SET_FILE_UNIX_LINK:
6727 : {
6728 0 : if (smb_fname == NULL) {
6729 : /* We must have a pathname for this. */
6730 0 : return NT_STATUS_INVALID_LEVEL;
6731 : }
6732 0 : status = smb_set_file_unix_link(conn, req, pdata,
6733 : total_data, smb_fname);
6734 0 : break;
6735 : }
6736 :
6737 0 : case SMB_SET_FILE_UNIX_HLINK:
6738 : {
6739 0 : if (smb_fname == NULL) {
6740 : /* We must have a pathname for this. */
6741 0 : return NT_STATUS_INVALID_LEVEL;
6742 : }
6743 0 : status = smb_set_file_unix_hlink(conn, req,
6744 : pdata, total_data,
6745 : smb_fname);
6746 0 : break;
6747 : }
6748 :
6749 : #if defined(HAVE_POSIX_ACLS)
6750 0 : case SMB_SET_POSIX_ACL:
6751 : {
6752 0 : status = smb_set_posix_acl(conn,
6753 : req,
6754 : pdata,
6755 : total_data,
6756 : fsp,
6757 : smb_fname);
6758 0 : break;
6759 : }
6760 : #endif
6761 :
6762 : #if defined(WITH_SMB1SERVER)
6763 0 : case SMB_SET_POSIX_LOCK:
6764 : {
6765 0 : if (fsp == NULL) {
6766 0 : return NT_STATUS_INVALID_LEVEL;
6767 : }
6768 0 : status = smb_set_posix_lock(conn, req,
6769 : pdata, total_data, fsp);
6770 0 : break;
6771 : }
6772 : #endif
6773 :
6774 0 : case SMB_POSIX_PATH_OPEN:
6775 : {
6776 0 : if (smb_fname == NULL) {
6777 : /* We must have a pathname for this. */
6778 0 : return NT_STATUS_INVALID_LEVEL;
6779 : }
6780 :
6781 0 : status = smb_posix_open(conn, req,
6782 : ppdata,
6783 : total_data,
6784 : smb_fname,
6785 : &data_return_size);
6786 0 : break;
6787 : }
6788 :
6789 0 : case SMB_POSIX_PATH_UNLINK:
6790 : {
6791 0 : if (smb_fname == NULL) {
6792 : /* We must have a pathname for this. */
6793 0 : return NT_STATUS_INVALID_LEVEL;
6794 : }
6795 :
6796 0 : status = smb_posix_unlink(conn, req,
6797 : pdata,
6798 : total_data,
6799 : smb_fname);
6800 0 : break;
6801 : }
6802 :
6803 0 : default:
6804 0 : return NT_STATUS_INVALID_LEVEL;
6805 : }
6806 :
6807 0 : if (!NT_STATUS_IS_OK(status)) {
6808 0 : return status;
6809 : }
6810 :
6811 0 : *ret_data_size = data_return_size;
6812 0 : return NT_STATUS_OK;
6813 : }
6814 :
6815 894 : NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
6816 : struct smb_request *req,
6817 : TALLOC_CTX *mem_ctx,
6818 : uint16_t info_level,
6819 : files_struct *fsp,
6820 : struct smb_filename *smb_fname,
6821 : char **ppdata, int total_data,
6822 : int *ret_data_size)
6823 : {
6824 894 : char *pdata = *ppdata;
6825 894 : NTSTATUS status = NT_STATUS_OK;
6826 894 : int data_return_size = 0;
6827 :
6828 894 : if (INFO_LEVEL_IS_UNIX(info_level)) {
6829 0 : if (!lp_smb1_unix_extensions()) {
6830 0 : return NT_STATUS_INVALID_LEVEL;
6831 : }
6832 0 : if (!req->posix_pathnames) {
6833 0 : return NT_STATUS_INVALID_LEVEL;
6834 : }
6835 0 : status = smbd_do_posix_setfilepathinfo(conn,
6836 : req,
6837 : req,
6838 : info_level,
6839 : smb_fname,
6840 : fsp,
6841 : ppdata,
6842 : total_data,
6843 : &data_return_size);
6844 0 : if (!NT_STATUS_IS_OK(status)) {
6845 0 : return status;
6846 : }
6847 0 : *ret_data_size = data_return_size;
6848 0 : return NT_STATUS_OK;
6849 : }
6850 :
6851 894 : *ret_data_size = 0;
6852 :
6853 894 : DEBUG(3,("smbd_do_setfilepathinfo: %s (%s) info_level=%d "
6854 : "totdata=%d\n", smb_fname_str_dbg(smb_fname),
6855 : fsp_fnum_dbg(fsp),
6856 : info_level, total_data));
6857 :
6858 894 : switch (info_level) {
6859 :
6860 0 : case SMB_INFO_STANDARD:
6861 : {
6862 0 : status = smb_set_info_standard(conn,
6863 : pdata,
6864 : total_data,
6865 : fsp,
6866 : smb_fname);
6867 0 : break;
6868 : }
6869 :
6870 0 : case SMB_INFO_SET_EA:
6871 : {
6872 0 : status = smb_info_set_ea(conn,
6873 : pdata,
6874 : total_data,
6875 : fsp,
6876 : smb_fname);
6877 0 : break;
6878 : }
6879 :
6880 63 : case SMB_SET_FILE_BASIC_INFO:
6881 : case SMB_FILE_BASIC_INFORMATION:
6882 : {
6883 63 : status = smb_set_file_basic_info(conn,
6884 : pdata,
6885 : total_data,
6886 : fsp,
6887 : smb_fname);
6888 63 : break;
6889 : }
6890 :
6891 0 : case SMB_FILE_ALLOCATION_INFORMATION:
6892 : case SMB_SET_FILE_ALLOCATION_INFO:
6893 : {
6894 0 : status = smb_set_file_allocation_info(conn, req,
6895 : pdata,
6896 : total_data,
6897 : fsp,
6898 : smb_fname);
6899 0 : break;
6900 : }
6901 :
6902 0 : case SMB_FILE_END_OF_FILE_INFORMATION:
6903 : case SMB_SET_FILE_END_OF_FILE_INFO:
6904 : {
6905 : /*
6906 : * XP/Win7 both fail after the createfile with
6907 : * SMB_SET_FILE_END_OF_FILE_INFO but not
6908 : * SMB_FILE_END_OF_FILE_INFORMATION (pass-through).
6909 : * The level is known here, so pass it down
6910 : * appropriately.
6911 : */
6912 0 : bool should_fail =
6913 : (info_level == SMB_SET_FILE_END_OF_FILE_INFO);
6914 :
6915 0 : status = smb_set_file_end_of_file_info(conn, req,
6916 : pdata,
6917 : total_data,
6918 : fsp,
6919 : smb_fname,
6920 : should_fail);
6921 0 : break;
6922 : }
6923 :
6924 806 : case SMB_FILE_DISPOSITION_INFORMATION:
6925 : case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
6926 : {
6927 : #if 0
6928 : /* JRA - We used to just ignore this on a path ?
6929 : * Shouldn't this be invalid level on a pathname
6930 : * based call ?
6931 : */
6932 : if (tran_call != TRANSACT2_SETFILEINFO) {
6933 : return ERROR_NT(NT_STATUS_INVALID_LEVEL);
6934 : }
6935 : #endif
6936 806 : status = smb_set_file_disposition_info(conn,
6937 : pdata,
6938 : total_data,
6939 : fsp,
6940 : smb_fname);
6941 806 : break;
6942 : }
6943 :
6944 0 : case SMB_FILE_POSITION_INFORMATION:
6945 : {
6946 0 : status = smb_file_position_information(conn,
6947 : pdata,
6948 : total_data,
6949 : fsp);
6950 0 : break;
6951 : }
6952 :
6953 0 : case SMB_FILE_FULL_EA_INFORMATION:
6954 : {
6955 0 : status = smb_set_file_full_ea_info(conn,
6956 : pdata,
6957 : total_data,
6958 : fsp);
6959 0 : break;
6960 : }
6961 :
6962 : /* From tridge Samba4 :
6963 : * MODE_INFORMATION in setfileinfo (I have no
6964 : * idea what "mode information" on a file is - it takes a value of 0,
6965 : * 2, 4 or 6. What could it be?).
6966 : */
6967 :
6968 0 : case SMB_FILE_MODE_INFORMATION:
6969 : {
6970 0 : status = smb_file_mode_information(conn,
6971 : pdata,
6972 : total_data);
6973 0 : break;
6974 : }
6975 :
6976 : /* [MS-SMB2] 3.3.5.21.1 states we MUST fail with STATUS_NOT_SUPPORTED. */
6977 0 : case SMB_FILE_VALID_DATA_LENGTH_INFORMATION:
6978 : case SMB_FILE_SHORT_NAME_INFORMATION:
6979 0 : return NT_STATUS_NOT_SUPPORTED;
6980 :
6981 0 : case SMB_FILE_RENAME_INFORMATION:
6982 : {
6983 0 : status = smb_file_rename_information(conn, req,
6984 : pdata, total_data,
6985 : fsp, smb_fname);
6986 0 : break;
6987 : }
6988 :
6989 21 : case SMB2_FILE_RENAME_INFORMATION_INTERNAL:
6990 : {
6991 : /* SMB2 rename information. */
6992 21 : status = smb2_file_rename_information(conn, req,
6993 : pdata, total_data,
6994 : fsp, smb_fname);
6995 21 : break;
6996 : }
6997 :
6998 4 : case SMB_FILE_LINK_INFORMATION:
6999 : {
7000 4 : status = smb_file_link_information(conn, req,
7001 : pdata, total_data,
7002 : fsp, smb_fname);
7003 4 : break;
7004 : }
7005 :
7006 0 : default:
7007 0 : return NT_STATUS_INVALID_LEVEL;
7008 : }
7009 :
7010 894 : if (!NT_STATUS_IS_OK(status)) {
7011 6 : return status;
7012 : }
7013 :
7014 888 : *ret_data_size = data_return_size;
7015 888 : return NT_STATUS_OK;
7016 : }
7017 :
7018 4 : static uint32_t generate_volume_serial_number(
7019 : const struct loadparm_substitution *lp_sub,
7020 : int snum)
7021 : {
7022 4 : int serial = lp_volume_serial_number(snum);
7023 8 : return serial != -1 ? serial:
7024 6 : str_checksum(lp_servicename(talloc_tos(), lp_sub, snum)) ^
7025 4 : (str_checksum(get_local_machine_name())<<16);
7026 : }
|