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