Keep track of the sparse status of an open file handle. Allows bypass of
[ira/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 "librpc/gen_ndr/ndr_xattr.h"
23 #include "../libcli/security/security.h"
24
25 static uint32_t filter_mode_by_protocol(uint32_t mode)
26 {
27         if (get_Protocol() <= PROTOCOL_LANMAN2) {
28                 DEBUG(10,("filter_mode_by_protocol: "
29                         "filtering result 0x%x to 0x%x\n",
30                         (unsigned int)mode,
31                         (unsigned int)(mode & 0x3f) ));
32                 mode &= 0x3f;
33         }
34         return mode;
35 }
36
37 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
38 {
39 #ifdef S_ISLNK
40 #if LINKS_READ_ONLY
41         if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
42                 return aRONLY;
43 #endif
44 #endif
45         return 0;
46 }
47
48 /****************************************************************************
49  Change a dos mode to a unix mode.
50     Base permission for files:
51          if creating file and inheriting (i.e. parent_dir != NULL)
52            apply read/write bits from parent directory.
53          else   
54            everybody gets read bit set
55          dos readonly is represented in unix by removing everyone's write bit
56          dos archive is represented in unix by the user's execute bit
57          dos system is represented in unix by the group's execute bit
58          dos hidden is represented in unix by the other's execute bit
59          if !inheriting {
60            Then apply create mask,
61            then add force bits.
62          }
63     Base permission for directories:
64          dos directory is represented in unix by unix's dir bit and the exec bit
65          if !inheriting {
66            Then apply create mask,
67            then add force bits.
68          }
69 ****************************************************************************/
70
71 mode_t unix_mode(connection_struct *conn, int dosmode,
72                  const struct smb_filename *smb_fname,
73                  const char *inherit_from_dir)
74 {
75         mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
76         mode_t dir_mode = 0; /* Mode of the inherit_from directory if
77                               * inheriting. */
78
79         if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
80                 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
81         }
82
83         if ((inherit_from_dir != NULL) && lp_inherit_perms(SNUM(conn))) {
84                 struct smb_filename *smb_fname_parent = NULL;
85                 NTSTATUS status;
86
87                 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
88                           smb_fname_str_dbg(smb_fname),
89                           inherit_from_dir));
90
91                 status = create_synthetic_smb_fname(talloc_tos(),
92                                                     inherit_from_dir, NULL,
93                                                     NULL, &smb_fname_parent);
94                 if (!NT_STATUS_IS_OK(status)) {
95                         DEBUG(1,("unix_mode(%s) failed, [dir %s]: %s\n",
96                                  smb_fname_str_dbg(smb_fname),
97                                  inherit_from_dir, nt_errstr(status)));
98                         return(0);
99                 }
100
101                 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
102                         DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
103                                  smb_fname_str_dbg(smb_fname),
104                                  inherit_from_dir, strerror(errno)));
105                         TALLOC_FREE(smb_fname_parent);
106                         return(0);      /* *** shouldn't happen! *** */
107                 }
108
109                 /* Save for later - but explicitly remove setuid bit for safety. */
110                 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
111                 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
112                          smb_fname_str_dbg(smb_fname), (int)dir_mode));
113                 /* Clear "result" */
114                 result = 0;
115                 TALLOC_FREE(smb_fname_parent);
116         } 
117
118         if (IS_DOS_DIR(dosmode)) {
119                 /* We never make directories read only for the owner as under DOS a user
120                 can always create a file in a read-only directory. */
121                 result |= (S_IFDIR | S_IWUSR);
122
123                 if (dir_mode) {
124                         /* Inherit mode of parent directory. */
125                         result |= dir_mode;
126                 } else {
127                         /* Provisionally add all 'x' bits */
128                         result |= (S_IXUSR | S_IXGRP | S_IXOTH);                 
129
130                         /* Apply directory mask */
131                         result &= lp_dir_mask(SNUM(conn));
132                         /* Add in force bits */
133                         result |= lp_force_dir_mode(SNUM(conn));
134                 }
135         } else { 
136                 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
137                         result |= S_IXUSR;
138
139                 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
140                         result |= S_IXGRP;
141
142                 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
143                         result |= S_IXOTH;  
144
145                 if (dir_mode) {
146                         /* Inherit 666 component of parent directory mode */
147                         result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
148                 } else {
149                         /* Apply mode mask */
150                         result &= lp_create_mask(SNUM(conn));
151                         /* Add in force bits */
152                         result |= lp_force_create_mode(SNUM(conn));
153                 }
154         }
155
156         DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname),
157                  (int)result));
158         return(result);
159 }
160
161 /****************************************************************************
162  Change a unix mode to a dos mode.
163 ****************************************************************************/
164
165 static uint32 dos_mode_from_sbuf(connection_struct *conn,
166                                  const struct smb_filename *smb_fname)
167 {
168         int result = 0;
169         enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
170
171         if (ro_opts == MAP_READONLY_YES) {
172                 /* Original Samba method - map inverse of user "w" bit. */
173                 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
174                         result |= aRONLY;
175                 }
176         } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
177                 /* Check actual permissions for read-only. */
178                 if (!can_write_to_file(conn, smb_fname)) {
179                         result |= aRONLY;
180                 }
181         } /* Else never set the readonly bit. */
182
183         if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
184                 result |= aARCH;
185
186         if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
187                 result |= aSYSTEM;
188
189         if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
190                 result |= aHIDDEN;   
191
192         if (S_ISDIR(smb_fname->st.st_ex_mode))
193                 result = aDIR | (result & aRONLY);
194
195         result |= set_link_read_only_flag(&smb_fname->st);
196
197         DEBUG(8,("dos_mode_from_sbuf returning "));
198
199         if (result & aHIDDEN) DEBUG(8, ("h"));
200         if (result & aRONLY ) DEBUG(8, ("r"));
201         if (result & aSYSTEM) DEBUG(8, ("s"));
202         if (result & aDIR   ) DEBUG(8, ("d"));
203         if (result & aARCH  ) DEBUG(8, ("a"));
204
205         DEBUG(8,("\n"));
206         return result;
207 }
208
209 /****************************************************************************
210  Get DOS attributes from an EA.
211  This can also pull the create time into the stat struct inside smb_fname.
212 ****************************************************************************/
213
214 static bool get_ea_dos_attribute(connection_struct *conn,
215                                  struct smb_filename *smb_fname,
216                                  uint32 *pattr)
217 {
218         struct xattr_DOSATTRIB dosattrib;
219         enum ndr_err_code ndr_err;
220         DATA_BLOB blob;
221         ssize_t sizeret;
222         fstring attrstr;
223         uint32_t dosattr;
224
225         if (!lp_store_dos_attributes(SNUM(conn))) {
226                 return False;
227         }
228
229         /* Don't reset pattr to zero as we may already have filename-based attributes we
230            need to preserve. */
231
232         sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
233                                    SAMBA_XATTR_DOS_ATTRIB, attrstr,
234                                    sizeof(attrstr));
235         if (sizeret == -1) {
236                 if (errno == ENOSYS
237 #if defined(ENOTSUP)
238                         || errno == ENOTSUP) {
239 #else
240                                 ) {
241 #endif
242                         DEBUG(1,("get_ea_dos_attribute: Cannot get attribute "
243                                  "from EA on file %s: Error = %s\n",
244                                  smb_fname_str_dbg(smb_fname),
245                                  strerror(errno)));
246                         set_store_dos_attributes(SNUM(conn), False);
247                 }
248                 return False;
249         }
250
251         blob.data = (uint8_t *)attrstr;
252         blob.length = sizeret;
253
254         ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
255                         (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
256
257         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
258                 DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
259                          "from EA on file %s: Error = %s\n",
260                          smb_fname_str_dbg(smb_fname),
261                          ndr_errstr(ndr_err)));
262                 return false;
263         }
264
265         DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
266                   smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));
267
268         switch (dosattrib.version) {
269                 case 0xFFFF:
270                         dosattr = dosattrib.info.compatinfoFFFF.attrib;
271                         break;
272                 case 1:
273                         dosattr = dosattrib.info.info1.attrib;
274                         if (!null_nttime(dosattrib.info.info1.create_time)) {
275                                 struct timespec create_time =
276                                         nt_time_to_unix_timespec(
277                                                 &dosattrib.info.info1.create_time);
278
279                                 update_stat_ex_create_time(&smb_fname->st,
280                                                         create_time);
281
282                                 DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
283                                         "set btime %s\n",
284                                         smb_fname_str_dbg(smb_fname),
285                                         time_to_asc(convert_timespec_to_time_t(
286                                                 create_time)) ));
287                         }
288                         break;
289                 case 2:
290                         dosattr = dosattrib.info.oldinfo2.attrib;
291                         /* Don't know what flags to check for this case. */
292                         break;
293                 case 3:
294                         dosattr = dosattrib.info.info3.attrib;
295                         if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
296                                         !null_nttime(dosattrib.info.info3.create_time)) {
297                                 struct timespec create_time =
298                                         nt_time_to_unix_timespec(
299                                                 &dosattrib.info.info3.create_time);
300
301                                 update_stat_ex_create_time(&smb_fname->st,
302                                                         create_time);
303
304                                 DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
305                                         "set btime %s\n",
306                                         smb_fname_str_dbg(smb_fname),
307                                         time_to_asc(convert_timespec_to_time_t(
308                                                 create_time)) ));
309                         }
310                         break;
311                         default:
312                                 DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
313                                          "file %s - %s\n", smb_fname_str_dbg(smb_fname),
314                                          attrstr));
315                         return false;
316         }
317
318         if (S_ISDIR(smb_fname->st.st_ex_mode)) {
319                 dosattr |= aDIR;
320         }
321         /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
322         *pattr = (uint32)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
323
324         DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
325
326         if (dosattr & aHIDDEN) DEBUG(8, ("h"));
327         if (dosattr & aRONLY ) DEBUG(8, ("r"));
328         if (dosattr & aSYSTEM) DEBUG(8, ("s"));
329         if (dosattr & aDIR   ) DEBUG(8, ("d"));
330         if (dosattr & aARCH  ) DEBUG(8, ("a"));
331
332         DEBUG(8,("\n"));
333
334         return True;
335 }
336
337 /****************************************************************************
338  Set DOS attributes in an EA.
339  Also sets the create time.
340 ****************************************************************************/
341
342 static bool set_ea_dos_attribute(connection_struct *conn,
343                                  struct smb_filename *smb_fname,
344                                  uint32 dosmode)
345 {
346         struct xattr_DOSATTRIB dosattrib;
347         enum ndr_err_code ndr_err;
348         DATA_BLOB blob;
349         files_struct *fsp = NULL;
350         bool ret = false;
351
352         if (!lp_store_dos_attributes(SNUM(conn))) {
353                 return False;
354         }
355
356         ZERO_STRUCT(dosattrib);
357         ZERO_STRUCT(blob);
358
359         dosattrib.version = 3;
360         dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
361                                         XATTR_DOSINFO_CREATE_TIME;
362         dosattrib.info.info3.attrib = dosmode;
363         unix_timespec_to_nt_time(&dosattrib.info.info3.create_time,
364                                 smb_fname->st.st_ex_btime);
365
366         DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
367                 (unsigned int)dosmode,
368                 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
369                 smb_fname_str_dbg(smb_fname) ));
370
371         ndr_err = ndr_push_struct_blob(
372                         &blob, talloc_tos(), &dosattrib,
373                         (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
374
375         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
376                 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
377                         ndr_errstr(ndr_err)));
378                 return false;
379         }
380
381         if (blob.data == NULL || blob.length == 0) {
382                 return false;
383         }
384
385         if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
386                              SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
387                              0) == -1) {
388                 if((errno != EPERM) && (errno != EACCES)) {
389                         if (errno == ENOSYS
390 #if defined(ENOTSUP)
391                                 || errno == ENOTSUP) {
392 #else
393                                 ) {
394 #endif
395                                 DEBUG(1,("set_ea_dos_attributes: Cannot set "
396                                          "attribute EA on file %s: Error = %s\n",
397                                          smb_fname_str_dbg(smb_fname),
398                                          strerror(errno) ));
399                                 set_store_dos_attributes(SNUM(conn), False);
400                         }
401                         return false;
402                 }
403
404                 /* We want DOS semantics, ie allow non owner with write permission to change the
405                         bits on a file. Just like file_ntimes below.
406                 */
407
408                 /* Check if we have write access. */
409                 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
410                         return false;
411
412                 /*
413                  * We need to open the file with write access whilst
414                  * still in our current user context. This ensures we
415                  * are not violating security in doing the setxattr.
416                  */
417
418                 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
419                                                       &fsp)))
420                         return ret;
421                 become_root();
422                 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
423                                      SAMBA_XATTR_DOS_ATTRIB, blob.data,
424                                      blob.length, 0) == 0) {
425                         ret = true;
426                 }
427                 unbecome_root();
428                 close_file_fchmod(NULL, fsp);
429                 return ret;
430         }
431         DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
432                 (unsigned int)dosmode,
433                 smb_fname_str_dbg(smb_fname)));
434         return true;
435 }
436
437 /****************************************************************************
438  Change a unix mode to a dos mode for an ms dfs link.
439 ****************************************************************************/
440
441 uint32 dos_mode_msdfs(connection_struct *conn,
442                       const struct smb_filename *smb_fname)
443 {
444         uint32 result = 0;
445
446         DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
447
448         if (!VALID_STAT(smb_fname->st)) {
449                 return 0;
450         }
451
452         /* First do any modifications that depend on the path name. */
453         /* hide files with a name starting with a . */
454         if (lp_hide_dot_files(SNUM(conn))) {
455                 const char *p = strrchr_m(smb_fname->base_name, '/');
456                 if (p) {
457                         p++;
458                 } else {
459                         p = smb_fname->base_name;
460                 }
461
462                 /* Only . and .. are not hidden. */
463                 if (p[0] == '.' && !((p[1] == '\0') ||
464                                 (p[1] == '.' && p[2] == '\0'))) {
465                         result |= aHIDDEN;
466                 }
467         }
468
469         result |= dos_mode_from_sbuf(conn, smb_fname);
470
471         /* Optimization : Only call is_hidden_path if it's not already
472            hidden. */
473         if (!(result & aHIDDEN) &&
474             IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
475                 result |= aHIDDEN;
476         }
477
478         if (result == 0) {
479                 result = FILE_ATTRIBUTE_NORMAL;
480         }
481
482         result = filter_mode_by_protocol(result);
483
484         DEBUG(8,("dos_mode_msdfs returning "));
485
486         if (result & aHIDDEN) DEBUG(8, ("h"));
487         if (result & aRONLY ) DEBUG(8, ("r"));
488         if (result & aSYSTEM) DEBUG(8, ("s"));
489         if (result & aDIR   ) DEBUG(8, ("d"));
490         if (result & aARCH  ) DEBUG(8, ("a"));
491         if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
492
493         DEBUG(8,("\n"));
494
495         return(result);
496 }
497
498 #ifdef HAVE_STAT_DOS_FLAGS
499 /****************************************************************************
500  Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
501 ****************************************************************************/
502
503 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
504 {
505         uint32_t dos_stat_flags = 0;
506
507         if (dosmode & aARCH)
508                 dos_stat_flags |= UF_DOS_ARCHIVE;
509         if (dosmode & aHIDDEN)
510                 dos_stat_flags |= UF_DOS_HIDDEN;
511         if (dosmode & aRONLY)
512                 dos_stat_flags |= UF_DOS_RO;
513         if (dosmode & aSYSTEM)
514                 dos_stat_flags |= UF_DOS_SYSTEM;
515         if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
516                 dos_stat_flags |= UF_DOS_NOINDEX;
517
518         return dos_stat_flags;
519 }
520
521 /****************************************************************************
522  Gets DOS attributes, accessed via st_ex_flags in the stat struct.
523 ****************************************************************************/
524
525 static bool get_stat_dos_flags(connection_struct *conn,
526                                const struct smb_filename *smb_fname,
527                                uint32_t *dosmode)
528 {
529         SMB_ASSERT(VALID_STAT(smb_fname->st));
530         SMB_ASSERT(dosmode);
531
532         if (!lp_store_dos_attributes(SNUM(conn))) {
533                 return false;
534         }
535
536         DEBUG(5, ("Getting stat dos attributes for %s.\n",
537                   smb_fname_str_dbg(smb_fname)));
538
539         if (smb_fname->st.st_ex_flags & UF_DOS_ARCHIVE)
540                 *dosmode |= aARCH;
541         if (smb_fname->st.st_ex_flags & UF_DOS_HIDDEN)
542                 *dosmode |= aHIDDEN;
543         if (smb_fname->st.st_ex_flags & UF_DOS_RO)
544                 *dosmode |= aRONLY;
545         if (smb_fname->st.st_ex_flags & UF_DOS_SYSTEM)
546                 *dosmode |= aSYSTEM;
547         if (smb_fname->st.st_ex_flags & UF_DOS_NOINDEX)
548                 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
549         if (smb_fname->st.st_ex_flags & FILE_ATTRIBUTE_SPARSE)
550                 *dosmode |= FILE_ATTRIBUTE_SPARSE;
551         if (S_ISDIR(smb_fname->st.st_ex_mode))
552                 *dosmode |= aDIR;
553
554         *dosmode |= set_link_read_only_flag(&smb_fname->st);
555
556         return true;
557 }
558
559 /****************************************************************************
560  Sets DOS attributes, stored in st_ex_flags of the inode.
561 ****************************************************************************/
562
563 static bool set_stat_dos_flags(connection_struct *conn,
564                                const struct smb_filename *smb_fname,
565                                uint32_t dosmode,
566                                bool *attributes_changed)
567 {
568         uint32_t new_flags = 0;
569         int error = 0;
570
571         SMB_ASSERT(VALID_STAT(smb_fname->st));
572         SMB_ASSERT(attributes_changed);
573
574         *attributes_changed = false;
575
576         if (!lp_store_dos_attributes(SNUM(conn))) {
577                 return false;
578         }
579
580         DEBUG(5, ("Setting stat dos attributes for %s.\n",
581                   smb_fname_str_dbg(smb_fname)));
582
583         new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) |
584                      dos_attributes_to_stat_dos_flags(dosmode);
585
586         /* Return early if no flags changed. */
587         if (new_flags == smb_fname->st.st_ex_flags)
588                 return true;
589
590         DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
591                   smb_fname->st.st_ex_flags));
592
593         /* Set new flags with chflags. */
594         error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags);
595         if (error) {
596                 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
597                           "file %s! errno=%d\n", new_flags,
598                           smb_fname_str_dbg(smb_fname), errno));
599                 return false;
600         }
601
602         *attributes_changed = true;
603         return true;
604 }
605 #endif /* HAVE_STAT_DOS_FLAGS */
606
607 /****************************************************************************
608  Change a unix mode to a dos mode.
609  May also read the create timespec into the stat struct in smb_fname
610  if "store dos attributes" is true.
611 ****************************************************************************/
612
613 uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
614 {
615         uint32 result = 0;
616         bool offline, used_stat_dos_flags = false;
617
618         DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
619
620         if (!VALID_STAT(smb_fname->st)) {
621                 return 0;
622         }
623
624         /* First do any modifications that depend on the path name. */
625         /* hide files with a name starting with a . */
626         if (lp_hide_dot_files(SNUM(conn))) {
627                 const char *p = strrchr_m(smb_fname->base_name,'/');
628                 if (p) {
629                         p++;
630                 } else {
631                         p = smb_fname->base_name;
632                 }
633
634                 /* Only . and .. are not hidden. */
635                 if (p[0] == '.' && !((p[1] == '\0') ||
636                                 (p[1] == '.' && p[2] == '\0'))) {
637                         result |= aHIDDEN;
638                 }
639         }
640
641 #ifdef HAVE_STAT_DOS_FLAGS
642         used_stat_dos_flags = get_stat_dos_flags(conn, smb_fname, &result);
643 #endif
644         if (!used_stat_dos_flags) {
645                 /* Get the DOS attributes from an EA by preference. */
646                 if (!get_ea_dos_attribute(conn, smb_fname, &result)) {
647                         result |= dos_mode_from_sbuf(conn, smb_fname);
648                 }
649         }
650
651         offline = SMB_VFS_IS_OFFLINE(conn, smb_fname->base_name, &smb_fname->st);
652         if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
653                 result |= FILE_ATTRIBUTE_OFFLINE;
654         }
655
656         /* Optimization : Only call is_hidden_path if it's not already
657            hidden. */
658         if (!(result & aHIDDEN) &&
659             IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
660                 result |= aHIDDEN;
661         }
662
663         if (result == 0) {
664                 result = FILE_ATTRIBUTE_NORMAL;
665         }
666
667         result = filter_mode_by_protocol(result);
668
669         DEBUG(8,("dos_mode returning "));
670
671         if (result & aHIDDEN) DEBUG(8, ("h"));
672         if (result & aRONLY ) DEBUG(8, ("r"));
673         if (result & aSYSTEM) DEBUG(8, ("s"));
674         if (result & aDIR   ) DEBUG(8, ("d"));
675         if (result & aARCH  ) DEBUG(8, ("a"));
676         if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
677
678         DEBUG(8,("\n"));
679
680         return(result);
681 }
682
683 /*******************************************************************
684  chmod a file - but preserve some bits.
685  If "store dos attributes" is also set it will store the create time
686  from the stat struct in smb_fname (in NTTIME format) in the EA
687  attribute also.
688 ********************************************************************/
689
690 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
691                      uint32 dosmode, const char *parent_dir, bool newfile)
692 {
693         int mask=0;
694         mode_t tmp;
695         mode_t unixmode;
696         int ret = -1, lret = -1;
697         uint32_t old_mode;
698         struct timespec new_create_timespec;
699
700         /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
701         dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
702
703         DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
704                   dosmode, smb_fname_str_dbg(smb_fname)));
705
706         unixmode = smb_fname->st.st_ex_mode;
707
708         get_acl_group_bits(conn, smb_fname->base_name,
709                            &smb_fname->st.st_ex_mode);
710
711         if (S_ISDIR(smb_fname->st.st_ex_mode))
712                 dosmode |= aDIR;
713         else
714                 dosmode &= ~aDIR;
715
716         new_create_timespec = smb_fname->st.st_ex_btime;
717
718         old_mode = dos_mode(conn, smb_fname);
719
720         if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
721                 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
722                         lret = SMB_VFS_SET_OFFLINE(conn, smb_fname->base_name);
723                         if (lret == -1) {
724                                 DEBUG(0, ("set_dos_mode: client has asked to "
725                                           "set FILE_ATTRIBUTE_OFFLINE to "
726                                           "%s/%s but there was an error while "
727                                           "setting it or it is not "
728                                           "supported.\n", parent_dir,
729                                           smb_fname_str_dbg(smb_fname)));
730                         }
731                 }
732         }
733
734         dosmode  &= ~FILE_ATTRIBUTE_OFFLINE;
735         old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
736
737         smb_fname->st.st_ex_btime = new_create_timespec;
738
739 #ifdef HAVE_STAT_DOS_FLAGS
740         {
741                 bool attributes_changed;
742
743                 if (set_stat_dos_flags(conn, smb_fname, dosmode,
744                                        &attributes_changed))
745                 {
746                         if (!newfile && attributes_changed) {
747                                 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
748                                     FILE_NOTIFY_CHANGE_ATTRIBUTES,
749                                     smb_fname->base_name);
750                         }
751                         smb_fname->st.st_ex_mode = unixmode;
752                         return 0;
753                 }
754         }
755 #endif
756         /* Store the DOS attributes in an EA by preference. */
757         if (set_ea_dos_attribute(conn, smb_fname, dosmode)) {
758                 if (!newfile) {
759                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
760                                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
761                                      smb_fname->base_name);
762                 }
763                 smb_fname->st.st_ex_mode = unixmode;
764                 return 0;
765         }
766
767         unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
768
769         /* preserve the s bits */
770         mask |= (S_ISUID | S_ISGID);
771
772         /* preserve the t bit */
773 #ifdef S_ISVTX
774         mask |= S_ISVTX;
775 #endif
776
777         /* possibly preserve the x bits */
778         if (!MAP_ARCHIVE(conn))
779                 mask |= S_IXUSR;
780         if (!MAP_SYSTEM(conn))
781                 mask |= S_IXGRP;
782         if (!MAP_HIDDEN(conn))
783                 mask |= S_IXOTH;
784
785         unixmode |= (smb_fname->st.st_ex_mode & mask);
786
787         /* if we previously had any r bits set then leave them alone */
788         if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
789                 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
790                 unixmode |= tmp;
791         }
792
793         /* if we previously had any w bits set then leave them alone 
794                 whilst adding in the new w bits, if the new mode is not rdonly */
795         if (!IS_DOS_READONLY(dosmode)) {
796                 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
797         }
798
799         ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
800         if (ret == 0) {
801                 if(!newfile || (lret != -1)) {
802                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
803                                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
804                                      smb_fname->base_name);
805                 }
806                 smb_fname->st.st_ex_mode = unixmode;
807                 return 0;
808         }
809
810         if((errno != EPERM) && (errno != EACCES))
811                 return -1;
812
813         if(!lp_dos_filemode(SNUM(conn)))
814                 return -1;
815
816         /* We want DOS semantics, ie allow non owner with write permission to change the
817                 bits on a file. Just like file_ntimes below.
818         */
819
820         /* Check if we have write access. */
821         if (CAN_WRITE(conn)) {
822                 /*
823                  * We need to open the file with write access whilst
824                  * still in our current user context. This ensures we
825                  * are not violating security in doing the fchmod.
826                  * This file open does *not* break any oplocks we are
827                  * holding. We need to review this.... may need to
828                  * break batch oplocks open by others. JRA.
829                  */
830                 files_struct *fsp;
831                 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
832                                      &fsp)))
833                         return -1;
834                 become_root();
835                 ret = SMB_VFS_FCHMOD(fsp, unixmode);
836                 unbecome_root();
837                 close_file_fchmod(NULL, fsp);
838                 if (!newfile) {
839                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
840                                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
841                                      smb_fname->base_name);
842                 }
843                 if (ret == 0) {
844                         smb_fname->st.st_ex_mode = unixmode;
845                 }
846         }
847
848         return( ret );
849 }
850
851
852 NTSTATUS file_set_sparse(connection_struct *conn,
853                          files_struct *fsp,
854                          bool sparse)
855 {
856         uint32_t old_dosmode;
857         uint32_t new_dosmode;
858         NTSTATUS status;
859
860         if (!CAN_WRITE(conn)) {
861                 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
862                         "on readonly share[%s]\n",
863                         smb_fname_str_dbg(fsp->fsp_name),
864                         sparse,
865                         lp_servicename(SNUM(conn))));
866                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
867         }
868
869         if (!(fsp->access_mask & FILE_WRITE_DATA) &&
870                         !(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
871                 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
872                         "access_mask[0x%08X] - access denied\n",
873                         smb_fname_str_dbg(fsp->fsp_name),
874                         sparse,
875                         fsp->access_mask));
876                 return NT_STATUS_ACCESS_DENIED;
877         }
878
879         DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
880                   sparse, smb_fname_str_dbg(fsp->fsp_name)));
881
882         if (!lp_store_dos_attributes(SNUM(conn))) {
883                 return NT_STATUS_INVALID_DEVICE_REQUEST;
884         }
885
886         status = vfs_stat_fsp(fsp);
887         if (!NT_STATUS_IS_OK(status)) {
888                 return status;
889         }
890
891         old_dosmode = dos_mode(conn, fsp->fsp_name);
892
893         if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
894                 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
895         } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
896                 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
897         } else {
898                 return NT_STATUS_OK;
899         }
900
901         /* Store the DOS attributes in an EA. */
902         if (!set_ea_dos_attribute(conn, fsp->fsp_name,
903                                   new_dosmode)) {
904                 if (errno == 0) {
905                         errno = EIO;
906                 }
907                 return map_nt_error_from_unix(errno);
908         }
909
910         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
911                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
912                      fsp->fsp_name->base_name);
913
914         fsp->is_sparse = sparse;
915
916         return NT_STATUS_OK;
917 }
918
919 /*******************************************************************
920  Wrapper around the VFS ntimes that possibly allows DOS semantics rather
921  than POSIX.
922 *******************************************************************/
923
924 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
925                 struct smb_file_time *ft)
926 {
927         int ret = -1;
928
929         errno = 0;
930
931         DEBUG(6, ("file_ntime: actime: %s",
932                   time_to_asc(convert_timespec_to_time_t(ft->atime))));
933         DEBUG(6, ("file_ntime: modtime: %s",
934                   time_to_asc(convert_timespec_to_time_t(ft->mtime))));
935         DEBUG(6, ("file_ntime: ctime: %s",
936                   time_to_asc(convert_timespec_to_time_t(ft->ctime))));
937         DEBUG(6, ("file_ntime: createtime: %s",
938                   time_to_asc(convert_timespec_to_time_t(ft->create_time))));
939
940         /* Don't update the time on read-only shares */
941         /* We need this as set_filetime (which can be called on
942            close and other paths) can end up calling this function
943            without the NEED_WRITE protection. Found by : 
944            Leo Weppelman <leo@wau.mis.ah.nl>
945         */
946
947         if (!CAN_WRITE(conn)) {
948                 return 0;
949         }
950
951         if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
952                 return 0;
953         }
954
955         if((errno != EPERM) && (errno != EACCES)) {
956                 return -1;
957         }
958
959         if(!lp_dos_filetimes(SNUM(conn))) {
960                 return -1;
961         }
962
963         /* We have permission (given by the Samba admin) to
964            break POSIX semantics and allow a user to change
965            the time on a file they don't own but can write to
966            (as DOS does).
967          */
968
969         /* Check if we have write access. */
970         if (can_write_to_file(conn, smb_fname)) {
971                 /* We are allowed to become root and change the filetime. */
972                 become_root();
973                 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
974                 unbecome_root();
975         }
976
977         return ret;
978 }
979
980 /******************************************************************
981  Force a "sticky" write time on a pathname. This will always be
982  returned on all future write time queries and set on close.
983 ******************************************************************/
984
985 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
986 {
987         if (null_timespec(mtime)) {
988                 return true;
989         }
990
991         if (!set_sticky_write_time(fileid, mtime)) {
992                 return false;
993         }
994
995         return true;
996 }
997
998 /******************************************************************
999  Force a "sticky" write time on an fsp. This will always be
1000  returned on all future write time queries and set on close.
1001 ******************************************************************/
1002
1003 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1004 {
1005         if (null_timespec(mtime)) {
1006                 return true;
1007         }
1008
1009         fsp->write_time_forced = true;
1010         TALLOC_FREE(fsp->update_write_time_event);
1011
1012         return set_sticky_write_time_path(fsp->file_id, mtime);
1013 }
1014
1015 /******************************************************************
1016  Set a create time EA.
1017 ******************************************************************/
1018
1019 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1020                                 const struct smb_filename *psmb_fname,
1021                                 struct timespec create_time)
1022 {
1023         NTSTATUS status;
1024         struct smb_filename *smb_fname = NULL;
1025         uint32_t dosmode;
1026         int ret;
1027
1028         if (!lp_store_dos_attributes(SNUM(conn))) {
1029                 return NT_STATUS_OK;
1030         }
1031
1032         status = create_synthetic_smb_fname(talloc_tos(),
1033                                 psmb_fname->base_name,
1034                                 NULL, &psmb_fname->st,
1035                                 &smb_fname);
1036
1037         if (!NT_STATUS_IS_OK(status)) {
1038                 return status;
1039         }
1040
1041         dosmode = dos_mode(conn, smb_fname);
1042
1043         smb_fname->st.st_ex_btime = create_time;
1044
1045         ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1046         if (ret == -1) {
1047                 map_nt_error_from_unix(errno);
1048         }
1049
1050         DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1051                 smb_fname_str_dbg(smb_fname)));
1052
1053         return NT_STATUS_OK;
1054 }
1055
1056 /******************************************************************
1057  Return a create time.
1058 ******************************************************************/
1059
1060 struct timespec get_create_timespec(connection_struct *conn,
1061                                 struct files_struct *fsp,
1062                                 const struct smb_filename *smb_fname)
1063 {
1064         return smb_fname->st.st_ex_btime;
1065 }
1066
1067 /******************************************************************
1068  Return a change time (may look at EA in future).
1069 ******************************************************************/
1070
1071 struct timespec get_change_timespec(connection_struct *conn,
1072                                 struct files_struct *fsp,
1073                                 const struct smb_filename *smb_fname)
1074 {
1075         return smb_fname->st.st_ex_mtime;
1076 }