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