Move checks inside file_set_sparse() to allow it to be called from anywhere.
[kamenim/samba.git] / source3 / smbd / dosmode.c
1 /* 
2    Unix SMB/CIFS implementation.
3    dos mode handling functions
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) James Peach 2006
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "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         *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
322
323         DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
324
325         if (dosattr & aHIDDEN) DEBUG(8, ("h"));
326         if (dosattr & aRONLY ) DEBUG(8, ("r"));
327         if (dosattr & aSYSTEM) DEBUG(8, ("s"));
328         if (dosattr & aDIR   ) DEBUG(8, ("d"));
329         if (dosattr & aARCH  ) DEBUG(8, ("a"));
330
331         DEBUG(8,("\n"));
332
333         return True;
334 }
335
336 /****************************************************************************
337  Set DOS attributes in an EA.
338  Also sets the create time.
339 ****************************************************************************/
340
341 static bool set_ea_dos_attribute(connection_struct *conn,
342                                  struct smb_filename *smb_fname,
343                                  uint32 dosmode)
344 {
345         struct xattr_DOSATTRIB dosattrib;
346         enum ndr_err_code ndr_err;
347         DATA_BLOB blob;
348         files_struct *fsp = NULL;
349         bool ret = false;
350
351         if (!lp_store_dos_attributes(SNUM(conn))) {
352                 return False;
353         }
354
355         ZERO_STRUCT(dosattrib);
356         ZERO_STRUCT(blob);
357
358         dosattrib.version = 3;
359         dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
360                                         XATTR_DOSINFO_CREATE_TIME;
361         dosattrib.info.info3.attrib = dosmode;
362         unix_timespec_to_nt_time(&dosattrib.info.info3.create_time,
363                                 smb_fname->st.st_ex_btime);
364
365         DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
366                 (unsigned int)dosmode,
367                 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
368                 smb_fname_str_dbg(smb_fname) ));
369
370         ndr_err = ndr_push_struct_blob(
371                         &blob, talloc_tos(), &dosattrib,
372                         (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
373
374         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
375                 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
376                         ndr_errstr(ndr_err)));
377                 return false;
378         }
379
380         if (blob.data == NULL || blob.length == 0) {
381                 return false;
382         }
383
384         if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
385                              SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
386                              0) == -1) {
387                 if((errno != EPERM) && (errno != EACCES)) {
388                         if (errno == ENOSYS
389 #if defined(ENOTSUP)
390                                 || errno == ENOTSUP) {
391 #else
392                                 ) {
393 #endif
394                                 DEBUG(1,("set_ea_dos_attributes: Cannot set "
395                                          "attribute EA on file %s: Error = %s\n",
396                                          smb_fname_str_dbg(smb_fname),
397                                          strerror(errno) ));
398                                 set_store_dos_attributes(SNUM(conn), False);
399                         }
400                         return false;
401                 }
402
403                 /* We want DOS semantics, ie allow non owner with write permission to change the
404                         bits on a file. Just like file_ntimes below.
405                 */
406
407                 /* Check if we have write access. */
408                 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
409                         return false;
410
411                 /*
412                  * We need to open the file with write access whilst
413                  * still in our current user context. This ensures we
414                  * are not violating security in doing the setxattr.
415                  */
416
417                 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
418                                                       &fsp)))
419                         return ret;
420                 become_root();
421                 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
422                                      SAMBA_XATTR_DOS_ATTRIB, blob.data,
423                                      blob.length, 0) == 0) {
424                         ret = true;
425                 }
426                 unbecome_root();
427                 close_file_fchmod(NULL, fsp);
428                 return ret;
429         }
430         DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
431                 (unsigned int)dosmode,
432                 smb_fname_str_dbg(smb_fname)));
433         return true;
434 }
435
436 /****************************************************************************
437  Change a unix mode to a dos mode for an ms dfs link.
438 ****************************************************************************/
439
440 uint32 dos_mode_msdfs(connection_struct *conn,
441                       const struct smb_filename *smb_fname)
442 {
443         uint32 result = 0;
444
445         DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
446
447         if (!VALID_STAT(smb_fname->st)) {
448                 return 0;
449         }
450
451         /* First do any modifications that depend on the path name. */
452         /* hide files with a name starting with a . */
453         if (lp_hide_dot_files(SNUM(conn))) {
454                 const char *p = strrchr_m(smb_fname->base_name, '/');
455                 if (p) {
456                         p++;
457                 } else {
458                         p = smb_fname->base_name;
459                 }
460
461                 /* Only . and .. are not hidden. */
462                 if (p[0] == '.' && !((p[1] == '\0') ||
463                                 (p[1] == '.' && p[2] == '\0'))) {
464                         result |= aHIDDEN;
465                 }
466         }
467
468         result |= dos_mode_from_sbuf(conn, smb_fname);
469
470         /* Optimization : Only call is_hidden_path if it's not already
471            hidden. */
472         if (!(result & aHIDDEN) &&
473             IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
474                 result |= aHIDDEN;
475         }
476
477         if (result == 0) {
478                 result = FILE_ATTRIBUTE_NORMAL;
479         }
480
481         result = filter_mode_by_protocol(result);
482
483         DEBUG(8,("dos_mode_msdfs returning "));
484
485         if (result & aHIDDEN) DEBUG(8, ("h"));
486         if (result & aRONLY ) DEBUG(8, ("r"));
487         if (result & aSYSTEM) DEBUG(8, ("s"));
488         if (result & aDIR   ) DEBUG(8, ("d"));
489         if (result & aARCH  ) DEBUG(8, ("a"));
490         if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
491
492         DEBUG(8,("\n"));
493
494         return(result);
495 }
496
497 #ifdef HAVE_STAT_DOS_FLAGS
498 /****************************************************************************
499  Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
500 ****************************************************************************/
501
502 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
503 {
504         uint32_t dos_stat_flags = 0;
505
506         if (dosmode & aARCH)
507                 dos_stat_flags |= UF_DOS_ARCHIVE;
508         if (dosmode & aHIDDEN)
509                 dos_stat_flags |= UF_DOS_HIDDEN;
510         if (dosmode & aRONLY)
511                 dos_stat_flags |= UF_DOS_RO;
512         if (dosmode & aSYSTEM)
513                 dos_stat_flags |= UF_DOS_SYSTEM;
514         if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
515                 dos_stat_flags |= UF_DOS_NOINDEX;
516
517         return dos_stat_flags;
518 }
519
520 /****************************************************************************
521  Gets DOS attributes, accessed via st_ex_flags in the stat struct.
522 ****************************************************************************/
523
524 static bool get_stat_dos_flags(connection_struct *conn,
525                                const struct smb_filename *smb_fname,
526                                uint32_t *dosmode)
527 {
528         SMB_ASSERT(VALID_STAT(smb_fname->st));
529         SMB_ASSERT(dosmode);
530
531         if (!lp_store_dos_attributes(SNUM(conn))) {
532                 return false;
533         }
534
535         DEBUG(5, ("Getting stat dos attributes for %s.\n",
536                   smb_fname_str_dbg(smb_fname)));
537
538         if (smb_fname->st.st_ex_flags & UF_DOS_ARCHIVE)
539                 *dosmode |= aARCH;
540         if (smb_fname->st.st_ex_flags & UF_DOS_HIDDEN)
541                 *dosmode |= aHIDDEN;
542         if (smb_fname->st.st_ex_flags & UF_DOS_RO)
543                 *dosmode |= aRONLY;
544         if (smb_fname->st.st_ex_flags & UF_DOS_SYSTEM)
545                 *dosmode |= aSYSTEM;
546         if (smb_fname->st.st_ex_flags & UF_DOS_NOINDEX)
547                 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
548         if (smb_fname->st.st_ex_flags & FILE_ATTRIBUTE_SPARSE)
549                 *dosmode |= FILE_ATTRIBUTE_SPARSE;
550         if (S_ISDIR(smb_fname->st.st_ex_mode))
551                 *dosmode |= aDIR;
552
553         *dosmode |= set_link_read_only_flag(&smb_fname->st);
554
555         return true;
556 }
557
558 /****************************************************************************
559  Sets DOS attributes, stored in st_ex_flags of the inode.
560 ****************************************************************************/
561
562 static bool set_stat_dos_flags(connection_struct *conn,
563                                const struct smb_filename *smb_fname,
564                                uint32_t dosmode,
565                                bool *attributes_changed)
566 {
567         uint32_t new_flags = 0;
568         int error = 0;
569
570         SMB_ASSERT(VALID_STAT(smb_fname->st));
571         SMB_ASSERT(attributes_changed);
572
573         *attributes_changed = false;
574
575         if (!lp_store_dos_attributes(SNUM(conn))) {
576                 return false;
577         }
578
579         DEBUG(5, ("Setting stat dos attributes for %s.\n",
580                   smb_fname_str_dbg(smb_fname)));
581
582         new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) |
583                      dos_attributes_to_stat_dos_flags(dosmode);
584
585         /* Return early if no flags changed. */
586         if (new_flags == smb_fname->st.st_ex_flags)
587                 return true;
588
589         DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
590                   smb_fname->st.st_ex_flags));
591
592         /* Set new flags with chflags. */
593         error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags);
594         if (error) {
595                 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
596                           "file %s! errno=%d\n", new_flags,
597                           smb_fname_str_dbg(smb_fname), errno));
598                 return false;
599         }
600
601         *attributes_changed = true;
602         return true;
603 }
604 #endif /* HAVE_STAT_DOS_FLAGS */
605
606 /****************************************************************************
607  Change a unix mode to a dos mode.
608  May also read the create timespec into the stat struct in smb_fname
609  if "store dos attributes" is true.
610 ****************************************************************************/
611
612 uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
613 {
614         uint32 result = 0;
615         bool offline, used_stat_dos_flags = false;
616
617         DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
618
619         if (!VALID_STAT(smb_fname->st)) {
620                 return 0;
621         }
622
623         /* First do any modifications that depend on the path name. */
624         /* hide files with a name starting with a . */
625         if (lp_hide_dot_files(SNUM(conn))) {
626                 const char *p = strrchr_m(smb_fname->base_name,'/');
627                 if (p) {
628                         p++;
629                 } else {
630                         p = smb_fname->base_name;
631                 }
632
633                 /* Only . and .. are not hidden. */
634                 if (p[0] == '.' && !((p[1] == '\0') ||
635                                 (p[1] == '.' && p[2] == '\0'))) {
636                         result |= aHIDDEN;
637                 }
638         }
639
640 #ifdef HAVE_STAT_DOS_FLAGS
641         used_stat_dos_flags = get_stat_dos_flags(conn, smb_fname, &result);
642 #endif
643         if (!used_stat_dos_flags) {
644                 /* Get the DOS attributes from an EA by preference. */
645                 if (!get_ea_dos_attribute(conn, smb_fname, &result)) {
646                         result |= dos_mode_from_sbuf(conn, smb_fname);
647                 }
648         }
649
650         offline = SMB_VFS_IS_OFFLINE(conn, smb_fname->base_name, &smb_fname->st);
651         if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
652                 result |= FILE_ATTRIBUTE_OFFLINE;
653         }
654
655         /* Optimization : Only call is_hidden_path if it's not already
656            hidden. */
657         if (!(result & aHIDDEN) &&
658             IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
659                 result |= aHIDDEN;
660         }
661
662         if (result == 0) {
663                 result = FILE_ATTRIBUTE_NORMAL;
664         }
665
666         result = filter_mode_by_protocol(result);
667
668         DEBUG(8,("dos_mode returning "));
669
670         if (result & aHIDDEN) DEBUG(8, ("h"));
671         if (result & aRONLY ) DEBUG(8, ("r"));
672         if (result & aSYSTEM) DEBUG(8, ("s"));
673         if (result & aDIR   ) DEBUG(8, ("d"));
674         if (result & aARCH  ) DEBUG(8, ("a"));
675         if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
676
677         DEBUG(8,("\n"));
678
679         return(result);
680 }
681
682 /*******************************************************************
683  chmod a file - but preserve some bits.
684  If "store dos attributes" is also set it will store the create time
685  from the stat struct in smb_fname (in NTTIME format) in the EA
686  attribute also.
687 ********************************************************************/
688
689 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
690                      uint32 dosmode, const char *parent_dir, bool newfile)
691 {
692         int mask=0;
693         mode_t tmp;
694         mode_t unixmode;
695         int ret = -1, lret = -1;
696         uint32_t old_mode;
697         struct timespec new_create_timespec;
698
699         /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
700         dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
701
702         DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
703                   dosmode, smb_fname_str_dbg(smb_fname)));
704
705         unixmode = smb_fname->st.st_ex_mode;
706
707         get_acl_group_bits(conn, smb_fname->base_name,
708                            &smb_fname->st.st_ex_mode);
709
710         if (S_ISDIR(smb_fname->st.st_ex_mode))
711                 dosmode |= aDIR;
712         else
713                 dosmode &= ~aDIR;
714
715         new_create_timespec = smb_fname->st.st_ex_btime;
716
717         old_mode = dos_mode(conn, smb_fname);
718
719         if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
720                 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
721                         lret = SMB_VFS_SET_OFFLINE(conn, smb_fname->base_name);
722                         if (lret == -1) {
723                                 DEBUG(0, ("set_dos_mode: client has asked to "
724                                           "set FILE_ATTRIBUTE_OFFLINE to "
725                                           "%s/%s but there was an error while "
726                                           "setting it or it is not "
727                                           "supported.\n", parent_dir,
728                                           smb_fname_str_dbg(smb_fname)));
729                         }
730                 }
731         }
732
733         dosmode  &= ~FILE_ATTRIBUTE_OFFLINE;
734         old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
735
736         smb_fname->st.st_ex_btime = new_create_timespec;
737
738 #ifdef HAVE_STAT_DOS_FLAGS
739         {
740                 bool attributes_changed;
741
742                 if (set_stat_dos_flags(conn, smb_fname, dosmode,
743                                        &attributes_changed))
744                 {
745                         if (!newfile && attributes_changed) {
746                                 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
747                                     FILE_NOTIFY_CHANGE_ATTRIBUTES,
748                                     smb_fname->base_name);
749                         }
750                         smb_fname->st.st_ex_mode = unixmode;
751                         return 0;
752                 }
753         }
754 #endif
755         /* Store the DOS attributes in an EA by preference. */
756         if (set_ea_dos_attribute(conn, smb_fname, dosmode)) {
757                 if (!newfile) {
758                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
759                                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
760                                      smb_fname->base_name);
761                 }
762                 smb_fname->st.st_ex_mode = unixmode;
763                 return 0;
764         }
765
766         unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
767
768         /* preserve the s bits */
769         mask |= (S_ISUID | S_ISGID);
770
771         /* preserve the t bit */
772 #ifdef S_ISVTX
773         mask |= S_ISVTX;
774 #endif
775
776         /* possibly preserve the x bits */
777         if (!MAP_ARCHIVE(conn))
778                 mask |= S_IXUSR;
779         if (!MAP_SYSTEM(conn))
780                 mask |= S_IXGRP;
781         if (!MAP_HIDDEN(conn))
782                 mask |= S_IXOTH;
783
784         unixmode |= (smb_fname->st.st_ex_mode & mask);
785
786         /* if we previously had any r bits set then leave them alone */
787         if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
788                 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
789                 unixmode |= tmp;
790         }
791
792         /* if we previously had any w bits set then leave them alone 
793                 whilst adding in the new w bits, if the new mode is not rdonly */
794         if (!IS_DOS_READONLY(dosmode)) {
795                 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
796         }
797
798         ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
799         if (ret == 0) {
800                 if(!newfile || (lret != -1)) {
801                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
802                                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
803                                      smb_fname->base_name);
804                 }
805                 smb_fname->st.st_ex_mode = unixmode;
806                 return 0;
807         }
808
809         if((errno != EPERM) && (errno != EACCES))
810                 return -1;
811
812         if(!lp_dos_filemode(SNUM(conn)))
813                 return -1;
814
815         /* We want DOS semantics, ie allow non owner with write permission to change the
816                 bits on a file. Just like file_ntimes below.
817         */
818
819         /* Check if we have write access. */
820         if (CAN_WRITE(conn)) {
821                 /*
822                  * We need to open the file with write access whilst
823                  * still in our current user context. This ensures we
824                  * are not violating security in doing the fchmod.
825                  * This file open does *not* break any oplocks we are
826                  * holding. We need to review this.... may need to
827                  * break batch oplocks open by others. JRA.
828                  */
829                 files_struct *fsp;
830                 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
831                                      &fsp)))
832                         return -1;
833                 become_root();
834                 ret = SMB_VFS_FCHMOD(fsp, unixmode);
835                 unbecome_root();
836                 close_file_fchmod(NULL, fsp);
837                 if (!newfile) {
838                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
839                                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
840                                      smb_fname->base_name);
841                 }
842                 if (ret == 0) {
843                         smb_fname->st.st_ex_mode = unixmode;
844                 }
845         }
846
847         return( ret );
848 }
849
850
851 NTSTATUS file_set_sparse(connection_struct *conn,
852                          files_struct *fsp,
853                          bool sparse)
854 {
855         uint32_t old_dosmode;
856         uint32_t new_dosmode;
857         NTSTATUS status;
858
859         if (!CAN_WRITE(conn)) {
860                 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
861                         "on readonly share[%s]\n",
862                         smb_fname_str_dbg(fsp->fsp_name),
863                         sparse,
864                         lp_servicename(SNUM(conn))));
865                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
866         }
867
868         if (!(fsp->access_mask & FILE_WRITE_DATA) &&
869                         !(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
870                 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
871                         "access_mask[0x%08X] - access denied\n",
872                         smb_fname_str_dbg(fsp->fsp_name),
873                         sparse,
874                         fsp->access_mask));
875                 return NT_STATUS_ACCESS_DENIED;
876         }
877
878         DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
879                   sparse, smb_fname_str_dbg(fsp->fsp_name)));
880
881         if (!lp_store_dos_attributes(SNUM(conn))) {
882                 return NT_STATUS_INVALID_DEVICE_REQUEST;
883         }
884
885         status = vfs_stat_fsp(fsp);
886         if (!NT_STATUS_IS_OK(status)) {
887                 return status;
888         }
889
890         old_dosmode = dos_mode(conn, fsp->fsp_name);
891
892         if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
893                 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
894         } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
895                 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
896         } else {
897                 return NT_STATUS_OK;
898         }
899
900         /* Store the DOS attributes in an EA. */
901         if (!set_ea_dos_attribute(conn, fsp->fsp_name,
902                                   new_dosmode)) {
903                 if (errno == 0) {
904                         errno = EIO;
905                 }
906                 return map_nt_error_from_unix(errno);
907         }
908
909         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
910                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
911                      fsp->fsp_name->base_name);
912
913         return NT_STATUS_OK;
914 }
915
916 /*******************************************************************
917  Wrapper around the VFS ntimes that possibly allows DOS semantics rather
918  than POSIX.
919 *******************************************************************/
920
921 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
922                 struct smb_file_time *ft)
923 {
924         int ret = -1;
925
926         errno = 0;
927
928         DEBUG(6, ("file_ntime: actime: %s",
929                   time_to_asc(convert_timespec_to_time_t(ft->atime))));
930         DEBUG(6, ("file_ntime: modtime: %s",
931                   time_to_asc(convert_timespec_to_time_t(ft->mtime))));
932         DEBUG(6, ("file_ntime: ctime: %s",
933                   time_to_asc(convert_timespec_to_time_t(ft->ctime))));
934         DEBUG(6, ("file_ntime: createtime: %s",
935                   time_to_asc(convert_timespec_to_time_t(ft->create_time))));
936
937         /* Don't update the time on read-only shares */
938         /* We need this as set_filetime (which can be called on
939            close and other paths) can end up calling this function
940            without the NEED_WRITE protection. Found by : 
941            Leo Weppelman <leo@wau.mis.ah.nl>
942         */
943
944         if (!CAN_WRITE(conn)) {
945                 return 0;
946         }
947
948         if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
949                 return 0;
950         }
951
952         if((errno != EPERM) && (errno != EACCES)) {
953                 return -1;
954         }
955
956         if(!lp_dos_filetimes(SNUM(conn))) {
957                 return -1;
958         }
959
960         /* We have permission (given by the Samba admin) to
961            break POSIX semantics and allow a user to change
962            the time on a file they don't own but can write to
963            (as DOS does).
964          */
965
966         /* Check if we have write access. */
967         if (can_write_to_file(conn, smb_fname)) {
968                 /* We are allowed to become root and change the filetime. */
969                 become_root();
970                 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
971                 unbecome_root();
972         }
973
974         return ret;
975 }
976
977 /******************************************************************
978  Force a "sticky" write time on a pathname. This will always be
979  returned on all future write time queries and set on close.
980 ******************************************************************/
981
982 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
983 {
984         if (null_timespec(mtime)) {
985                 return true;
986         }
987
988         if (!set_sticky_write_time(fileid, mtime)) {
989                 return false;
990         }
991
992         return true;
993 }
994
995 /******************************************************************
996  Force a "sticky" write time on an fsp. This will always be
997  returned on all future write time queries and set on close.
998 ******************************************************************/
999
1000 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1001 {
1002         if (null_timespec(mtime)) {
1003                 return true;
1004         }
1005
1006         fsp->write_time_forced = true;
1007         TALLOC_FREE(fsp->update_write_time_event);
1008
1009         return set_sticky_write_time_path(fsp->file_id, mtime);
1010 }
1011
1012 /******************************************************************
1013  Set a create time EA.
1014 ******************************************************************/
1015
1016 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1017                                 const struct smb_filename *psmb_fname,
1018                                 struct timespec create_time)
1019 {
1020         NTSTATUS status;
1021         struct smb_filename *smb_fname = NULL;
1022         uint32_t dosmode;
1023         int ret;
1024
1025         if (!lp_store_dos_attributes(SNUM(conn))) {
1026                 return NT_STATUS_OK;
1027         }
1028
1029         status = create_synthetic_smb_fname(talloc_tos(),
1030                                 psmb_fname->base_name,
1031                                 NULL, &psmb_fname->st,
1032                                 &smb_fname);
1033
1034         if (!NT_STATUS_IS_OK(status)) {
1035                 return status;
1036         }
1037
1038         dosmode = dos_mode(conn, smb_fname);
1039
1040         smb_fname->st.st_ex_btime = create_time;
1041
1042         ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1043         if (ret == -1) {
1044                 map_nt_error_from_unix(errno);
1045         }
1046
1047         DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1048                 smb_fname_str_dbg(smb_fname)));
1049
1050         return NT_STATUS_OK;
1051 }
1052
1053 /******************************************************************
1054  Return a create time.
1055 ******************************************************************/
1056
1057 struct timespec get_create_timespec(connection_struct *conn,
1058                                 struct files_struct *fsp,
1059                                 const struct smb_filename *smb_fname)
1060 {
1061         return smb_fname->st.st_ex_btime;
1062 }
1063
1064 /******************************************************************
1065  Return a change time (may look at EA in future).
1066 ******************************************************************/
1067
1068 struct timespec get_change_timespec(connection_struct *conn,
1069                                 struct files_struct *fsp,
1070                                 const struct smb_filename *smb_fname)
1071 {
1072         return smb_fname->st.st_ex_mtime;
1073 }