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