vfs: remove dirfsp arg from SMB_VFS_CREATE_FILE()
[bbaumbach/samba-autobuild/.git] / source3 / smbd / dosmode.c
1 /* 
2    Unix SMB/CIFS implementation.
3    dos mode handling functions
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) James Peach 2006
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "globals.h"
23 #include "system/filesys.h"
24 #include "librpc/gen_ndr/ndr_xattr.h"
25 #include "librpc/gen_ndr/ioctl.h"
26 #include "../libcli/security/security.h"
27 #include "smbd/smbd.h"
28 #include "lib/param/loadparm.h"
29 #include "lib/util/tevent_ntstatus.h"
30 #include "lib/util/string_wrappers.h"
31
32 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
33                                 const struct smb_filename *smb_fname,
34                                 files_struct **ret_fsp,
35                                 bool *need_close);
36
37 static void dos_mode_debug_print(const char *func, uint32_t mode)
38 {
39         fstring modestr;
40
41         if (DEBUGLEVEL < DBGLVL_INFO) {
42                 return;
43         }
44
45         modestr[0] = '\0';
46
47         if (mode & FILE_ATTRIBUTE_HIDDEN) {
48                 fstrcat(modestr, "h");
49         }
50         if (mode & FILE_ATTRIBUTE_READONLY) {
51                 fstrcat(modestr, "r");
52         }
53         if (mode & FILE_ATTRIBUTE_SYSTEM) {
54                 fstrcat(modestr, "s");
55         }
56         if (mode & FILE_ATTRIBUTE_DIRECTORY) {
57                 fstrcat(modestr, "d");
58         }
59         if (mode & FILE_ATTRIBUTE_ARCHIVE) {
60                 fstrcat(modestr, "a");
61         }
62         if (mode & FILE_ATTRIBUTE_SPARSE) {
63                 fstrcat(modestr, "[sparse]");
64         }
65         if (mode & FILE_ATTRIBUTE_OFFLINE) {
66                 fstrcat(modestr, "[offline]");
67         }
68         if (mode & FILE_ATTRIBUTE_COMPRESSED) {
69                 fstrcat(modestr, "[compressed]");
70         }
71
72         DBG_INFO("%s returning (0x%x): \"%s\"\n", func, (unsigned)mode,
73                  modestr);
74 }
75
76 static uint32_t filter_mode_by_protocol(uint32_t mode)
77 {
78         if (get_Protocol() <= PROTOCOL_LANMAN2) {
79                 DEBUG(10,("filter_mode_by_protocol: "
80                         "filtering result 0x%x to 0x%x\n",
81                         (unsigned int)mode,
82                         (unsigned int)(mode & 0x3f) ));
83                 mode &= 0x3f;
84         }
85         return mode;
86 }
87
88 /****************************************************************************
89  Change a dos mode to a unix mode.
90     Base permission for files:
91          if creating file and inheriting (i.e. parent_dir != NULL)
92            apply read/write bits from parent directory.
93          else   
94            everybody gets read bit set
95          dos readonly is represented in unix by removing everyone's write bit
96          dos archive is represented in unix by the user's execute bit
97          dos system is represented in unix by the group's execute bit
98          dos hidden is represented in unix by the other's execute bit
99          if !inheriting {
100            Then apply create mask,
101            then add force bits.
102          }
103     Base permission for directories:
104          dos directory is represented in unix by unix's dir bit and the exec bit
105          if !inheriting {
106            Then apply create mask,
107            then add force bits.
108          }
109 ****************************************************************************/
110
111 mode_t unix_mode(connection_struct *conn, int dosmode,
112                  const struct smb_filename *smb_fname,
113                  struct smb_filename *smb_fname_parent)
114 {
115         mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
116         mode_t dir_mode = 0; /* Mode of the inherit_from directory if
117                               * inheriting. */
118
119         if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
120                 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
121         }
122
123         if ((smb_fname_parent != NULL) && lp_inherit_permissions(SNUM(conn))) {
124                 DBG_DEBUG("[%s] inheriting from [%s]\n",
125                           smb_fname_str_dbg(smb_fname),
126                           smb_fname_str_dbg(smb_fname_parent));
127
128                 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
129                         DBG_ERR("stat failed [%s]: %s\n",
130                                 smb_fname_str_dbg(smb_fname_parent),
131                                 strerror(errno));
132                         return(0);      /* *** shouldn't happen! *** */
133                 }
134
135                 /* Save for later - but explicitly remove setuid bit for safety. */
136                 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
137                 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
138                          smb_fname_str_dbg(smb_fname), (int)dir_mode));
139                 /* Clear "result" */
140                 result = 0;
141         } 
142
143         if (IS_DOS_DIR(dosmode)) {
144                 /* We never make directories read only for the owner as under DOS a user
145                 can always create a file in a read-only directory. */
146                 result |= (S_IFDIR | S_IWUSR);
147
148                 if (dir_mode) {
149                         /* Inherit mode of parent directory. */
150                         result |= dir_mode;
151                 } else {
152                         /* Provisionally add all 'x' bits */
153                         result |= (S_IXUSR | S_IXGRP | S_IXOTH);                 
154
155                         /* Apply directory mask */
156                         result &= lp_directory_mask(SNUM(conn));
157                         /* Add in force bits */
158                         result |= lp_force_directory_mode(SNUM(conn));
159                 }
160         } else { 
161                 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
162                         result |= S_IXUSR;
163
164                 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
165                         result |= S_IXGRP;
166
167                 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
168                         result |= S_IXOTH;  
169
170                 if (dir_mode) {
171                         /* Inherit 666 component of parent directory mode */
172                         result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
173                 } else {
174                         /* Apply mode mask */
175                         result &= lp_create_mask(SNUM(conn));
176                         /* Add in force bits */
177                         result |= lp_force_create_mode(SNUM(conn));
178                 }
179         }
180
181         DBG_INFO("unix_mode(%s) returning 0%o\n",
182                  smb_fname_str_dbg(smb_fname), (int)result);
183
184         return(result);
185 }
186
187 /****************************************************************************
188  Change a unix mode to a dos mode.
189 ****************************************************************************/
190
191 static uint32_t dos_mode_from_sbuf(connection_struct *conn,
192                                  const struct smb_filename *smb_fname)
193 {
194         int result = 0;
195         enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
196
197 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
198         /* if we can find out if a file is immutable we should report it r/o */
199         if (smb_fname->st.st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
200                 result |= FILE_ATTRIBUTE_READONLY;
201         }
202 #endif
203         if (ro_opts == MAP_READONLY_YES) {
204                 /* Original Samba method - map inverse of user "w" bit. */
205                 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
206                         result |= FILE_ATTRIBUTE_READONLY;
207                 }
208         } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
209                 /* Check actual permissions for read-only. */
210                 if (!can_write_to_file(conn,
211                                 conn->cwd_fsp,
212                                 smb_fname))
213                 {
214                         result |= FILE_ATTRIBUTE_READONLY;
215                 }
216         } /* Else never set the readonly bit. */
217
218         if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
219                 result |= FILE_ATTRIBUTE_ARCHIVE;
220
221         if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
222                 result |= FILE_ATTRIBUTE_SYSTEM;
223
224         if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
225                 result |= FILE_ATTRIBUTE_HIDDEN;
226
227         if (S_ISDIR(smb_fname->st.st_ex_mode))
228                 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
229
230         dos_mode_debug_print(__func__, result);
231
232         return result;
233 }
234
235 /****************************************************************************
236  Get DOS attributes from an EA.
237  This can also pull the create time into the stat struct inside smb_fname.
238 ****************************************************************************/
239
240 NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
241                                   DATA_BLOB blob,
242                                   uint32_t *pattr)
243 {
244         struct xattr_DOSATTRIB dosattrib;
245         enum ndr_err_code ndr_err;
246         uint32_t dosattr;
247
248         ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
249                         (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
250
251         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
252                 DBG_WARNING("bad ndr decode "
253                             "from EA on file %s: Error = %s\n",
254                             smb_fname_str_dbg(smb_fname),
255                             ndr_errstr(ndr_err));
256                 return ndr_map_error2ntstatus(ndr_err);
257         }
258
259         DBG_DEBUG("%s attr = %s\n",
260                   smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex);
261
262         switch (dosattrib.version) {
263         case 0xFFFF:
264                 dosattr = dosattrib.info.compatinfoFFFF.attrib;
265                 break;
266         case 1:
267                 dosattr = dosattrib.info.info1.attrib;
268                 if (!null_nttime(dosattrib.info.info1.create_time)) {
269                         struct timespec create_time =
270                                 nt_time_to_unix_timespec(
271                                         dosattrib.info.info1.create_time);
272
273                         update_stat_ex_create_time(&smb_fname->st,
274                                                    create_time);
275
276                         DBG_DEBUG("file %s case 1 set btime %s\n",
277                                   smb_fname_str_dbg(smb_fname),
278                                   time_to_asc(convert_timespec_to_time_t(
279                                                       create_time)));
280                 }
281                 break;
282         case 2:
283                 dosattr = dosattrib.info.oldinfo2.attrib;
284                 /* Don't know what flags to check for this case. */
285                 break;
286         case 3:
287                 dosattr = dosattrib.info.info3.attrib;
288                 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
289                     !null_nttime(dosattrib.info.info3.create_time)) {
290                         struct timespec create_time =
291                                 nt_time_to_full_timespec(
292                                         dosattrib.info.info3.create_time);
293
294                         update_stat_ex_create_time(&smb_fname->st,
295                                                    create_time);
296
297                         DBG_DEBUG("file %s case 3 set btime %s\n",
298                                   smb_fname_str_dbg(smb_fname),
299                                   time_to_asc(convert_timespec_to_time_t(
300                                                       create_time)));
301                 }
302                 break;
303         case 4:
304         {
305                 struct xattr_DosInfo4 *info = &dosattrib.info.info4;
306
307                 dosattr = info->attrib;
308
309                 if ((info->valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
310                     !null_nttime(info->create_time))
311                 {
312                         struct timespec creat_time;
313
314                         creat_time = nt_time_to_full_timespec(info->create_time);
315                         update_stat_ex_create_time(&smb_fname->st, creat_time);
316
317                         DBG_DEBUG("file [%s] creation time [%s]\n",
318                                 smb_fname_str_dbg(smb_fname),
319                                 nt_time_string(talloc_tos(), info->create_time));
320                 }
321
322                 if (info->valid_flags & XATTR_DOSINFO_ITIME) {
323                         struct timespec itime;
324                         uint64_t file_id;
325
326                         itime = nt_time_to_unix_timespec(info->itime);
327                         if (smb_fname->st.st_ex_iflags &
328                             ST_EX_IFLAG_CALCULATED_ITIME)
329                         {
330                                 update_stat_ex_itime(&smb_fname->st, itime);
331                         }
332
333                         file_id = make_file_id_from_itime(&smb_fname->st);
334                         if (smb_fname->st.st_ex_iflags &
335                             ST_EX_IFLAG_CALCULATED_FILE_ID)
336                         {
337                                 update_stat_ex_file_id(&smb_fname->st, file_id);
338                         }
339
340                         DBG_DEBUG("file [%s] itime [%s] fileid [%"PRIx64"]\n",
341                                 smb_fname_str_dbg(smb_fname),
342                                 nt_time_string(talloc_tos(), info->itime),
343                                 file_id);
344                 }
345                 break;
346         }
347         default:
348                 DBG_WARNING("Badly formed DOSATTRIB on file %s - %s\n",
349                             smb_fname_str_dbg(smb_fname), blob.data);
350                 /* Should this be INTERNAL_ERROR? */
351                 return NT_STATUS_INVALID_PARAMETER;
352         }
353
354         if (S_ISDIR(smb_fname->st.st_ex_mode)) {
355                 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
356         }
357
358         /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
359         *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
360
361         dos_mode_debug_print(__func__, *pattr);
362
363         return NT_STATUS_OK;
364 }
365
366 NTSTATUS get_ea_dos_attribute(connection_struct *conn,
367                               struct smb_filename *smb_fname,
368                               uint32_t *pattr)
369 {
370         DATA_BLOB blob;
371         ssize_t sizeret;
372         fstring attrstr;
373         NTSTATUS status;
374
375         if (!lp_store_dos_attributes(SNUM(conn))) {
376                 return NT_STATUS_NOT_IMPLEMENTED;
377         }
378
379         /* Don't reset pattr to zero as we may already have filename-based attributes we
380            need to preserve. */
381
382         sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
383                                    SAMBA_XATTR_DOS_ATTRIB, attrstr,
384                                    sizeof(attrstr));
385         if (sizeret == -1 && errno == EACCES) {
386                 int saved_errno = 0;
387
388                 /*
389                  * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
390                  * an Existing File" FILE_LIST_DIRECTORY on a directory implies
391                  * FILE_READ_ATTRIBUTES for directory entries. Being able to
392                  * stat() a file implies FILE_LIST_DIRECTORY for the directory
393                  * containing the file.
394                  */
395
396                 if (!VALID_STAT(smb_fname->st)) {
397                         /*
398                          * Safety net: dos_mode() already checks this, but as we
399                          * become root based on this, add an additional layer of
400                          * defense.
401                          */
402                         DBG_ERR("Rejecting root override, invalid stat [%s]\n",
403                                 smb_fname_str_dbg(smb_fname));
404                         return NT_STATUS_ACCESS_DENIED;
405                 }
406
407                 become_root();
408                 sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
409                                            SAMBA_XATTR_DOS_ATTRIB,
410                                            attrstr,
411                                            sizeof(attrstr));
412                 if (sizeret == -1) {
413                         saved_errno = errno;
414                 }
415                 unbecome_root();
416
417                 if (saved_errno != 0) {
418                         errno = saved_errno;
419                 }
420         }
421         if (sizeret == -1) {
422                 DBG_INFO("Cannot get attribute "
423                          "from EA on file %s: Error = %s\n",
424                          smb_fname_str_dbg(smb_fname), strerror(errno));
425                 return map_nt_error_from_unix(errno);
426         }
427
428         blob.data = (uint8_t *)attrstr;
429         blob.length = sizeret;
430
431         status = parse_dos_attribute_blob(smb_fname, blob, pattr);
432         if (!NT_STATUS_IS_OK(status)) {
433                 return status;
434         }
435
436         return NT_STATUS_OK;
437 }
438
439 /****************************************************************************
440  Set DOS attributes in an EA.
441  Also sets the create time.
442 ****************************************************************************/
443
444 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
445                               const struct smb_filename *smb_fname,
446                               uint32_t dosmode)
447 {
448         struct xattr_DOSATTRIB dosattrib;
449         enum ndr_err_code ndr_err;
450         DATA_BLOB blob;
451         int ret;
452
453         if (!lp_store_dos_attributes(SNUM(conn))) {
454                 return NT_STATUS_NOT_IMPLEMENTED;
455         }
456
457         /*
458          * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in
459          * vfs_default via DMAPI if that is enabled.
460          */
461         dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
462
463         ZERO_STRUCT(dosattrib);
464         ZERO_STRUCT(blob);
465
466         dosattrib.version = 4;
467         dosattrib.info.info4.valid_flags = XATTR_DOSINFO_ATTRIB |
468                                         XATTR_DOSINFO_CREATE_TIME;
469         dosattrib.info.info4.attrib = dosmode;
470         dosattrib.info.info4.create_time = full_timespec_to_nt_time(
471                 &smb_fname->st.st_ex_btime);
472
473         if (!(smb_fname->st.st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) {
474                 dosattrib.info.info4.valid_flags |= XATTR_DOSINFO_ITIME;
475                 dosattrib.info.info4.itime = full_timespec_to_nt_time(
476                         &smb_fname->st.st_ex_itime);
477         }
478
479         DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
480                 (unsigned int)dosmode,
481                 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
482                 smb_fname_str_dbg(smb_fname) ));
483
484         ndr_err = ndr_push_struct_blob(
485                         &blob, talloc_tos(), &dosattrib,
486                         (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
487
488         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
489                 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
490                         ndr_errstr(ndr_err)));
491                 return ndr_map_error2ntstatus(ndr_err);
492         }
493
494         if (blob.data == NULL || blob.length == 0) {
495                 /* Should this be INTERNAL_ERROR? */
496                 return NT_STATUS_INVALID_PARAMETER;
497         }
498
499         ret = SMB_VFS_SETXATTR(conn, smb_fname,
500                                SAMBA_XATTR_DOS_ATTRIB,
501                                blob.data, blob.length, 0);
502         if (ret != 0) {
503                 NTSTATUS status = NT_STATUS_OK;
504                 bool need_close = false;
505                 files_struct *fsp = NULL;
506                 bool set_dosmode_ok = false;
507
508                 if ((errno != EPERM) && (errno != EACCES)) {
509                         DBG_INFO("Cannot set "
510                                  "attribute EA on file %s: Error = %s\n",
511                                  smb_fname_str_dbg(smb_fname), strerror(errno));
512                         return map_nt_error_from_unix(errno);
513                 }
514
515                 /* We want DOS semantics, ie allow non owner with write permission to change the
516                         bits on a file. Just like file_ntimes below.
517                 */
518
519                 /* Check if we have write access. */
520                 if (!CAN_WRITE(conn)) {
521                         return NT_STATUS_ACCESS_DENIED;
522                 }
523
524                 status = smbd_check_access_rights(conn,
525                                         conn->cwd_fsp,
526                                         smb_fname,
527                                         false,
528                                         FILE_WRITE_ATTRIBUTES);
529                 if (NT_STATUS_IS_OK(status)) {
530                         set_dosmode_ok = true;
531                 }
532
533                 if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
534                         set_dosmode_ok = can_write_to_file(conn,
535                                                 conn->cwd_fsp,
536                                                 smb_fname);
537                 }
538
539                 if (!set_dosmode_ok) {
540                         return NT_STATUS_ACCESS_DENIED;
541                 }
542
543                 /*
544                  * We need to get an open file handle to do the
545                  * metadata operation under root.
546                  */
547
548                 status = get_file_handle_for_metadata(conn,
549                                                 smb_fname,
550                                                 &fsp,
551                                                 &need_close);
552                 if (!NT_STATUS_IS_OK(status)) {
553                         return status;
554                 }
555
556                 become_root();
557                 ret = SMB_VFS_FSETXATTR(fsp,
558                                         SAMBA_XATTR_DOS_ATTRIB,
559                                         blob.data, blob.length, 0);
560                 if (ret == 0) {
561                         status = NT_STATUS_OK;
562                 }
563                 unbecome_root();
564                 if (need_close) {
565                         close_file(NULL, fsp, NORMAL_CLOSE);
566                 }
567                 return status;
568         }
569         DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
570                 (unsigned int)dosmode,
571                 smb_fname_str_dbg(smb_fname)));
572         return NT_STATUS_OK;
573 }
574
575 /****************************************************************************
576  Change a unix mode to a dos mode for an ms dfs link.
577 ****************************************************************************/
578
579 uint32_t dos_mode_msdfs(connection_struct *conn,
580                       const struct smb_filename *smb_fname)
581 {
582         uint32_t result = 0;
583
584         DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
585
586         if (!VALID_STAT(smb_fname->st)) {
587                 return 0;
588         }
589
590         /* First do any modifications that depend on the path name. */
591         /* hide files with a name starting with a . */
592         if (lp_hide_dot_files(SNUM(conn))) {
593                 const char *p = strrchr_m(smb_fname->base_name, '/');
594                 if (p) {
595                         p++;
596                 } else {
597                         p = smb_fname->base_name;
598                 }
599
600                 /* Only . and .. are not hidden. */
601                 if (p[0] == '.' && !((p[1] == '\0') ||
602                                 (p[1] == '.' && p[2] == '\0'))) {
603                         result |= FILE_ATTRIBUTE_HIDDEN;
604                 }
605         }
606
607         result |= dos_mode_from_sbuf(conn, smb_fname);
608
609         /* Optimization : Only call is_hidden_path if it's not already
610            hidden. */
611         if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
612             IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
613                 result |= FILE_ATTRIBUTE_HIDDEN;
614         }
615
616         if (result == 0) {
617                 result = FILE_ATTRIBUTE_NORMAL;
618         }
619
620         result = filter_mode_by_protocol(result);
621
622         /*
623          * Add in that it is a reparse point
624          */
625         result |= FILE_ATTRIBUTE_REPARSE_POINT;
626
627         dos_mode_debug_print(__func__, result);
628
629         return(result);
630 }
631
632 /*
633  * check whether a file or directory is flagged as compressed.
634  */
635 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
636                                           struct smb_filename *smb_fname,
637                                           bool *is_compressed)
638 {
639         NTSTATUS status;
640         uint16_t compression_fmt;
641         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
642         if (tmp_ctx == NULL) {
643                 status = NT_STATUS_NO_MEMORY;
644                 goto err_out;
645         }
646
647         status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
648                                          &compression_fmt);
649         if (!NT_STATUS_IS_OK(status)) {
650                 goto err_ctx_free;
651         }
652
653         if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
654                 *is_compressed = true;
655         } else {
656                 *is_compressed = false;
657         }
658         status = NT_STATUS_OK;
659
660 err_ctx_free:
661         talloc_free(tmp_ctx);
662 err_out:
663         return status;
664 }
665
666 static uint32_t dos_mode_from_name(connection_struct *conn,
667                                    const struct smb_filename *smb_fname,
668                                    uint32_t dosmode)
669 {
670         const char *p = NULL;
671         uint32_t result = dosmode;
672
673         if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
674             lp_hide_dot_files(SNUM(conn)))
675         {
676                 p = strrchr_m(smb_fname->base_name, '/');
677                 if (p) {
678                         p++;
679                 } else {
680                         p = smb_fname->base_name;
681                 }
682
683                 /* Only . and .. are not hidden. */
684                 if ((p[0] == '.') &&
685                     !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0')))
686                 {
687                         result |= FILE_ATTRIBUTE_HIDDEN;
688                 }
689         }
690
691         if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
692             IS_HIDDEN_PATH(conn, smb_fname->base_name))
693         {
694                 result |= FILE_ATTRIBUTE_HIDDEN;
695         }
696
697         return result;
698 }
699
700 static uint32_t dos_mode_post(uint32_t dosmode,
701                               connection_struct *conn,
702                               struct smb_filename *smb_fname,
703                               const char *func)
704 {
705         NTSTATUS status;
706
707         /*
708          * According to MS-FSA a stream name does not have
709          * separate DOS attribute metadata, so we must return
710          * the DOS attribute from the base filename. With one caveat,
711          * a non-default stream name can never be a directory.
712          *
713          * As this is common to all streams data stores, we handle
714          * it here instead of inside all stream VFS modules.
715          *
716          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
717          */
718
719         if (is_named_stream(smb_fname)) {
720                 /* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
721                 dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
722         }
723
724         if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
725                 bool compressed = false;
726
727                 status = dos_mode_check_compressed(conn, smb_fname,
728                                                    &compressed);
729                 if (NT_STATUS_IS_OK(status) && compressed) {
730                         dosmode |= FILE_ATTRIBUTE_COMPRESSED;
731                 }
732         }
733
734         dosmode |= dos_mode_from_name(conn, smb_fname, dosmode);
735
736         if (S_ISDIR(smb_fname->st.st_ex_mode)) {
737                 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
738         } else if (dosmode == 0) {
739                 dosmode = FILE_ATTRIBUTE_NORMAL;
740         }
741
742         dosmode = filter_mode_by_protocol(dosmode);
743
744         dos_mode_debug_print(func, dosmode);
745         return dosmode;
746 }
747
748 /****************************************************************************
749  Change a unix mode to a dos mode.
750  May also read the create timespec into the stat struct in smb_fname
751  if "store dos attributes" is true.
752 ****************************************************************************/
753
754 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
755 {
756         uint32_t result = 0;
757         NTSTATUS status = NT_STATUS_OK;
758
759         DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
760
761         if (!VALID_STAT(smb_fname->st)) {
762                 return 0;
763         }
764
765         /* Get the DOS attributes via the VFS if we can */
766         status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &result);
767         if (!NT_STATUS_IS_OK(status)) {
768                 /*
769                  * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
770                  */
771                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
772                         result |= dos_mode_from_sbuf(conn, smb_fname);
773                 }
774         }
775
776         result = dos_mode_post(result, conn, smb_fname, __func__);
777         return result;
778 }
779
780 struct dos_mode_at_state {
781         files_struct *dir_fsp;
782         struct smb_filename *smb_fname;
783         uint32_t dosmode;
784 };
785
786 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq);
787
788 struct tevent_req *dos_mode_at_send(TALLOC_CTX *mem_ctx,
789                                     struct tevent_context *ev,
790                                     files_struct *dir_fsp,
791                                     struct smb_filename *smb_fname)
792 {
793         struct tevent_req *req = NULL;
794         struct dos_mode_at_state *state = NULL;
795         struct tevent_req *subreq = NULL;
796
797         DBG_DEBUG("%s\n", smb_fname_str_dbg(smb_fname));
798
799         req = tevent_req_create(mem_ctx, &state,
800                                 struct dos_mode_at_state);
801         if (req == NULL) {
802                 return NULL;
803         }
804
805         *state = (struct dos_mode_at_state) {
806                 .dir_fsp = dir_fsp,
807                 .smb_fname = smb_fname,
808         };
809
810         if (!VALID_STAT(smb_fname->st)) {
811                 tevent_req_done(req);
812                 return tevent_req_post(req, ev);
813         }
814
815         subreq = SMB_VFS_GET_DOS_ATTRIBUTES_SEND(state,
816                                                  ev,
817                                                  dir_fsp,
818                                                  smb_fname);
819         if (tevent_req_nomem(subreq, req)) {
820                 return tevent_req_post(req, ev);
821         }
822         tevent_req_set_callback(subreq, dos_mode_at_vfs_get_dosmode_done, req);
823
824         return req;
825 }
826
827 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
828 {
829         struct tevent_req *req =
830                 tevent_req_callback_data(subreq,
831                 struct tevent_req);
832         struct dos_mode_at_state *state =
833                 tevent_req_data(req,
834                 struct dos_mode_at_state);
835         char *path = NULL;
836         struct smb_filename *smb_path = NULL;
837         struct vfs_aio_state aio_state;
838         NTSTATUS status;
839         bool ok;
840
841         /*
842          * Make sure we run as the user again
843          */
844         ok = change_to_user_and_service_by_fsp(state->dir_fsp);
845         SMB_ASSERT(ok);
846
847         status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV(subreq,
848                                                  &aio_state,
849                                                  &state->dosmode);
850         TALLOC_FREE(subreq);
851         if (!NT_STATUS_IS_OK(status)) {
852                 /*
853                  * Both the sync dos_mode() as well as the async
854                  * dos_mode_at_[send|recv] have no real error return, the only
855                  * unhandled error is when the stat info in smb_fname is not
856                  * valid (cf the checks in dos_mode() and dos_mode_at_send().
857                  *
858                  * If SMB_VFS_GET_DOS_ATTRIBUTES[_SEND|_RECV] fails we must call
859                  * dos_mode_post() which also does the mapping of a last ressort
860                  * from S_IFMT(st_mode).
861                  *
862                  * Only if we get NT_STATUS_NOT_IMPLEMENTED from a stacked VFS
863                  * module we must fallback to sync processing.
864                  */
865                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
866                         /*
867                          * state->dosmode should still be 0, but reset
868                          * it to be sure.
869                          */
870                         state->dosmode = 0;
871                         status = NT_STATUS_OK;
872                 }
873         }
874         if (NT_STATUS_IS_OK(status)) {
875                 state->dosmode = dos_mode_post(state->dosmode,
876                                                state->dir_fsp->conn,
877                                                state->smb_fname,
878                                                __func__);
879                 tevent_req_done(req);
880                 return;
881         }
882
883         /*
884          * Fall back to sync dos_mode() if we got NOT_IMPLEMENTED.
885          */
886
887         path = talloc_asprintf(state,
888                                "%s/%s",
889                                state->dir_fsp->fsp_name->base_name,
890                                state->smb_fname->base_name);
891         if (tevent_req_nomem(path, req)) {
892                 return;
893         }
894
895         smb_path = synthetic_smb_fname(state,
896                                        path,
897                                        NULL,
898                                        &state->smb_fname->st,
899                                        state->smb_fname->twrp,
900                                        0);
901         if (tevent_req_nomem(smb_path, req)) {
902                 return;
903         }
904
905         state->dosmode = dos_mode(state->dir_fsp->conn, smb_path);
906         tevent_req_done(req);
907         return;
908 }
909
910 NTSTATUS dos_mode_at_recv(struct tevent_req *req, uint32_t *dosmode)
911 {
912         struct dos_mode_at_state *state =
913                 tevent_req_data(req,
914                 struct dos_mode_at_state);
915         NTSTATUS status;
916
917         if (tevent_req_is_nterror(req, &status)) {
918                 tevent_req_received(req);
919                 return status;
920         }
921
922         *dosmode = state->dosmode;
923         tevent_req_received(req);
924         return NT_STATUS_OK;
925 }
926
927 /*******************************************************************
928  chmod a file - but preserve some bits.
929  If "store dos attributes" is also set it will store the create time
930  from the stat struct in smb_fname (in NTTIME format) in the EA
931  attribute also.
932 ********************************************************************/
933
934 int file_set_dosmode(connection_struct *conn,
935                      struct smb_filename *smb_fname,
936                      uint32_t dosmode,
937                      struct smb_filename *parent_dir,
938                      bool newfile)
939 {
940         int mask=0;
941         mode_t tmp;
942         mode_t unixmode;
943         int ret = -1, lret = -1;
944         files_struct *fsp = NULL;
945         bool need_close = false;
946         NTSTATUS status;
947
948         if (!CAN_WRITE(conn)) {
949                 errno = EROFS;
950                 return -1;
951         }
952
953         dosmode &= SAMBA_ATTRIBUTES_MASK;
954
955         DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
956                   dosmode, smb_fname_str_dbg(smb_fname)));
957
958         unixmode = smb_fname->st.st_ex_mode;
959
960         get_acl_group_bits(conn, smb_fname,
961                         &smb_fname->st.st_ex_mode);
962
963         if (S_ISDIR(smb_fname->st.st_ex_mode))
964                 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
965         else
966                 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
967
968         /* Store the DOS attributes in an EA by preference. */
969         status = SMB_VFS_SET_DOS_ATTRIBUTES(conn, smb_fname, dosmode);
970         if (NT_STATUS_IS_OK(status)) {
971                 if (!newfile) {
972                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
973                                 FILE_NOTIFY_CHANGE_ATTRIBUTES,
974                                 smb_fname->base_name);
975                 }
976                 smb_fname->st.st_ex_mode = unixmode;
977                 return 0;
978         } else {
979                 /*
980                  * Only fall back to using UNIX modes if
981                  * we get NOT_IMPLEMENTED.
982                  */
983                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
984                         errno = map_errno_from_nt_status(status);
985                         return -1;
986                 }
987         }
988
989         /* Fall back to UNIX modes. */
990         unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
991
992         /* preserve the file type bits */
993         mask |= S_IFMT;
994
995         /* preserve the s bits */
996         mask |= (S_ISUID | S_ISGID);
997
998         /* preserve the t bit */
999 #ifdef S_ISVTX
1000         mask |= S_ISVTX;
1001 #endif
1002
1003         /* possibly preserve the x bits */
1004         if (!MAP_ARCHIVE(conn))
1005                 mask |= S_IXUSR;
1006         if (!MAP_SYSTEM(conn))
1007                 mask |= S_IXGRP;
1008         if (!MAP_HIDDEN(conn))
1009                 mask |= S_IXOTH;
1010
1011         unixmode |= (smb_fname->st.st_ex_mode & mask);
1012
1013         /* if we previously had any r bits set then leave them alone */
1014         if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
1015                 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
1016                 unixmode |= tmp;
1017         }
1018
1019         /* if we previously had any w bits set then leave them alone 
1020                 whilst adding in the new w bits, if the new mode is not rdonly */
1021         if (!IS_DOS_READONLY(dosmode)) {
1022                 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
1023         }
1024
1025         /*
1026          * From the chmod 2 man page:
1027          *
1028          * "If the calling process is not privileged, and the group of the file
1029          * does not match the effective group ID of the process or one of its
1030          * supplementary group IDs, the S_ISGID bit will be turned off, but
1031          * this will not cause an error to be returned."
1032          *
1033          * Simply refuse to do the chmod in this case.
1034          */
1035
1036         if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
1037                         geteuid() != sec_initial_uid() &&
1038                         !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
1039                 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
1040                         "set for directory %s\n",
1041                         smb_fname_str_dbg(smb_fname)));
1042                 errno = EPERM;
1043                 return -1;
1044         }
1045
1046         ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
1047         if (ret == 0) {
1048                 if(!newfile || (lret != -1)) {
1049                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1050                                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
1051                                      smb_fname->base_name);
1052                 }
1053                 smb_fname->st.st_ex_mode = unixmode;
1054                 return 0;
1055         }
1056
1057         if((errno != EPERM) && (errno != EACCES))
1058                 return -1;
1059
1060         if(!lp_dos_filemode(SNUM(conn)))
1061                 return -1;
1062
1063         /* We want DOS semantics, ie allow non owner with write permission to change the
1064                 bits on a file. Just like file_ntimes below.
1065         */
1066
1067         if (!can_write_to_file(conn,
1068                         conn->cwd_fsp,
1069                         smb_fname))
1070         {
1071                 errno = EACCES;
1072                 return -1;
1073         }
1074
1075         /*
1076          * We need to get an open file handle to do the
1077          * metadata operation under root.
1078          */
1079
1080         status = get_file_handle_for_metadata(conn,
1081                                               smb_fname,
1082                                               &fsp,
1083                                               &need_close);
1084         if (!NT_STATUS_IS_OK(status)) {
1085                 errno = map_errno_from_nt_status(status);
1086                 return -1;
1087         }
1088
1089         become_root();
1090         ret = SMB_VFS_FCHMOD(fsp, unixmode);
1091         unbecome_root();
1092         if (need_close) {
1093                 close_file(NULL, fsp, NORMAL_CLOSE);
1094         }
1095         if (!newfile) {
1096                 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1097                              FILE_NOTIFY_CHANGE_ATTRIBUTES,
1098                              smb_fname->base_name);
1099         }
1100         if (ret == 0) {
1101                 smb_fname->st.st_ex_mode = unixmode;
1102         }
1103
1104         return( ret );
1105 }
1106
1107
1108 NTSTATUS file_set_sparse(connection_struct *conn,
1109                          files_struct *fsp,
1110                          bool sparse)
1111 {
1112         const struct loadparm_substitution *lp_sub =
1113                 loadparm_s3_global_substitution();
1114         uint32_t old_dosmode;
1115         uint32_t new_dosmode;
1116         NTSTATUS status;
1117
1118         if (!CAN_WRITE(conn)) {
1119                 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1120                         "on readonly share[%s]\n",
1121                         smb_fname_str_dbg(fsp->fsp_name),
1122                         sparse,
1123                         lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1124                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1125         }
1126
1127         /*
1128          * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
1129          * following access flags are granted.
1130          */
1131         if ((fsp->access_mask & (FILE_WRITE_DATA
1132                                 | FILE_WRITE_ATTRIBUTES
1133                                 | SEC_FILE_APPEND_DATA)) == 0) {
1134                 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1135                         "access_mask[0x%08X] - access denied\n",
1136                         smb_fname_str_dbg(fsp->fsp_name),
1137                         sparse,
1138                         fsp->access_mask));
1139                 return NT_STATUS_ACCESS_DENIED;
1140         }
1141
1142         if (fsp->fsp_flags.is_directory) {
1143                 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
1144                           (sparse ? "set" : "clear"),
1145                           smb_fname_str_dbg(fsp->fsp_name)));
1146                 return NT_STATUS_INVALID_PARAMETER;
1147         }
1148
1149         if (IS_IPC(conn) || IS_PRINT(conn)) {
1150                 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
1151                           (sparse ? "set" : "clear")));
1152                 return NT_STATUS_INVALID_PARAMETER;
1153         }
1154
1155         DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
1156                   sparse, smb_fname_str_dbg(fsp->fsp_name)));
1157
1158         if (!lp_store_dos_attributes(SNUM(conn))) {
1159                 return NT_STATUS_INVALID_DEVICE_REQUEST;
1160         }
1161
1162         status = vfs_stat_fsp(fsp);
1163         if (!NT_STATUS_IS_OK(status)) {
1164                 return status;
1165         }
1166
1167         old_dosmode = dos_mode(conn, fsp->fsp_name);
1168
1169         if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1170                 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
1171         } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1172                 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
1173         } else {
1174                 return NT_STATUS_OK;
1175         }
1176
1177         /* Store the DOS attributes in an EA. */
1178         status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
1179         if (!NT_STATUS_IS_OK(status)) {
1180                 return status;
1181         }
1182
1183         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1184                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
1185                      fsp->fsp_name->base_name);
1186
1187         fsp->fsp_flags.is_sparse = sparse;
1188
1189         return NT_STATUS_OK;
1190 }
1191
1192 /*******************************************************************
1193  Wrapper around the VFS ntimes that possibly allows DOS semantics rather
1194  than POSIX.
1195 *******************************************************************/
1196
1197 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
1198                 struct smb_file_time *ft)
1199 {
1200         int ret = -1;
1201
1202         errno = 0;
1203
1204         DEBUG(6, ("file_ntime: actime: %s",
1205                   time_to_asc(convert_timespec_to_time_t(ft->atime))));
1206         DEBUG(6, ("file_ntime: modtime: %s",
1207                   time_to_asc(convert_timespec_to_time_t(ft->mtime))));
1208         DEBUG(6, ("file_ntime: ctime: %s",
1209                   time_to_asc(convert_timespec_to_time_t(ft->ctime))));
1210         DEBUG(6, ("file_ntime: createtime: %s",
1211                   time_to_asc(convert_timespec_to_time_t(ft->create_time))));
1212
1213         /* Don't update the time on read-only shares */
1214         /* We need this as set_filetime (which can be called on
1215            close and other paths) can end up calling this function
1216            without the NEED_WRITE protection. Found by : 
1217            Leo Weppelman <leo@wau.mis.ah.nl>
1218         */
1219
1220         if (!CAN_WRITE(conn)) {
1221                 return 0;
1222         }
1223
1224         if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
1225                 return 0;
1226         }
1227
1228         if((errno != EPERM) && (errno != EACCES)) {
1229                 return -1;
1230         }
1231
1232         if(!lp_dos_filetimes(SNUM(conn))) {
1233                 return -1;
1234         }
1235
1236         /* We have permission (given by the Samba admin) to
1237            break POSIX semantics and allow a user to change
1238            the time on a file they don't own but can write to
1239            (as DOS does).
1240          */
1241
1242         /* Check if we have write access. */
1243         if (can_write_to_file(conn,
1244                         conn->cwd_fsp,
1245                         smb_fname))
1246         {
1247                 /* We are allowed to become root and change the filetime. */
1248                 become_root();
1249                 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1250                 unbecome_root();
1251         }
1252
1253         return ret;
1254 }
1255
1256 /******************************************************************
1257  Force a "sticky" write time on a pathname. This will always be
1258  returned on all future write time queries and set on close.
1259 ******************************************************************/
1260
1261 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1262 {
1263         if (is_omit_timespec(&mtime)) {
1264                 return true;
1265         }
1266
1267         if (!set_sticky_write_time(fileid, mtime)) {
1268                 return false;
1269         }
1270
1271         return true;
1272 }
1273
1274 /******************************************************************
1275  Force a "sticky" write time on an fsp. This will always be
1276  returned on all future write time queries and set on close.
1277 ******************************************************************/
1278
1279 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1280 {
1281         if (is_omit_timespec(&mtime)) {
1282                 return true;
1283         }
1284
1285         fsp->fsp_flags.write_time_forced = true;
1286         TALLOC_FREE(fsp->update_write_time_event);
1287
1288         return set_sticky_write_time_path(fsp->file_id, mtime);
1289 }
1290
1291 /******************************************************************
1292  Set a create time EA.
1293 ******************************************************************/
1294
1295 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1296                                 const struct smb_filename *psmb_fname,
1297                                 struct timespec create_time)
1298 {
1299         struct smb_filename *smb_fname;
1300         uint32_t dosmode;
1301         int ret;
1302
1303         if (!lp_store_dos_attributes(SNUM(conn))) {
1304                 return NT_STATUS_OK;
1305         }
1306
1307         smb_fname = synthetic_smb_fname(talloc_tos(),
1308                                         psmb_fname->base_name,
1309                                         NULL,
1310                                         &psmb_fname->st,
1311                                         psmb_fname->twrp,
1312                                         psmb_fname->flags);
1313
1314         if (smb_fname == NULL) {
1315                 return NT_STATUS_NO_MEMORY;
1316         }
1317
1318         dosmode = dos_mode(conn, smb_fname);
1319
1320         smb_fname->st.st_ex_btime = create_time;
1321
1322         ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1323         if (ret == -1) {
1324                 return map_nt_error_from_unix(errno);
1325         }
1326
1327         DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1328                 smb_fname_str_dbg(smb_fname)));
1329
1330         return NT_STATUS_OK;
1331 }
1332
1333 /******************************************************************
1334  Return a create time.
1335 ******************************************************************/
1336
1337 struct timespec get_create_timespec(connection_struct *conn,
1338                                 struct files_struct *fsp,
1339                                 const struct smb_filename *smb_fname)
1340 {
1341         return smb_fname->st.st_ex_btime;
1342 }
1343
1344 /******************************************************************
1345  Return a change time (may look at EA in future).
1346 ******************************************************************/
1347
1348 struct timespec get_change_timespec(connection_struct *conn,
1349                                 struct files_struct *fsp,
1350                                 const struct smb_filename *smb_fname)
1351 {
1352         return smb_fname->st.st_ex_mtime;
1353 }
1354
1355 /****************************************************************************
1356  Get a real open file handle we can do meta-data operations on. As it's
1357  going to be used under root access only on meta-data we should look for
1358  any existing open file handle first, and use that in preference (also to
1359  avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1360 ****************************************************************************/
1361
1362 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1363                                 const struct smb_filename *smb_fname,
1364                                 files_struct **ret_fsp,
1365                                 bool *need_close)
1366 {
1367         NTSTATUS status;
1368         files_struct *fsp;
1369         struct file_id file_id;
1370         struct smb_filename *smb_fname_cp = NULL;
1371
1372         *need_close = false;
1373
1374         if (!VALID_STAT(smb_fname->st)) {
1375                 return NT_STATUS_INVALID_PARAMETER;
1376         }
1377
1378         file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1379
1380         for(fsp = file_find_di_first(conn->sconn, file_id);
1381                         fsp;
1382                         fsp = file_find_di_next(fsp)) {
1383                 if (fsp->fh->fd != -1) {
1384                         *ret_fsp = fsp;
1385                         return NT_STATUS_OK;
1386                 }
1387         }
1388
1389         smb_fname_cp = cp_smb_filename(talloc_tos(),
1390                                         smb_fname);
1391         if (smb_fname_cp == NULL) {
1392                 return NT_STATUS_NO_MEMORY;
1393         }
1394
1395         /* Opens an INTERNAL_OPEN_ONLY write handle. */
1396         status = SMB_VFS_CREATE_FILE(
1397                 conn,                                   /* conn */
1398                 NULL,                                   /* req */
1399                 smb_fname_cp,                           /* fname */
1400                 FILE_WRITE_ATTRIBUTES,                  /* access_mask */
1401                 (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
1402                         FILE_SHARE_DELETE),
1403                 FILE_OPEN,                              /* create_disposition*/
1404                 0,                                      /* create_options */
1405                 0,                                      /* file_attributes */
1406                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
1407                 NULL,                                   /* lease */
1408                 0,                                      /* allocation_size */
1409                 0,                                      /* private_flags */
1410                 NULL,                                   /* sd */
1411                 NULL,                                   /* ea_list */
1412                 ret_fsp,                                /* result */
1413                 NULL,                                   /* pinfo */
1414                 NULL, NULL);                            /* create context */
1415
1416         TALLOC_FREE(smb_fname_cp);
1417
1418         if (NT_STATUS_IS_OK(status)) {
1419                 *need_close = true;
1420         }
1421         return status;
1422 }