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