s4:smbd/open: add missing TALLOC_FREE(frame) to inherit_new_acl()
[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         if (result & FILE_ATTRIBUTE_OFFLINE ) DEBUG(8, ("[offline]"));
688
689         DEBUG(8,("\n"));
690
691         return(result);
692 }
693
694 /*******************************************************************
695  chmod a file - but preserve some bits.
696  If "store dos attributes" is also set it will store the create time
697  from the stat struct in smb_fname (in NTTIME format) in the EA
698  attribute also.
699 ********************************************************************/
700
701 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
702                      uint32 dosmode, const char *parent_dir, bool newfile)
703 {
704         int mask=0;
705         mode_t tmp;
706         mode_t unixmode;
707         int ret = -1, lret = -1;
708         uint32_t old_mode;
709         struct timespec new_create_timespec;
710
711         /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
712         dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
713
714         DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
715                   dosmode, smb_fname_str_dbg(smb_fname)));
716
717         unixmode = smb_fname->st.st_ex_mode;
718
719         get_acl_group_bits(conn, smb_fname->base_name,
720                            &smb_fname->st.st_ex_mode);
721
722         if (S_ISDIR(smb_fname->st.st_ex_mode))
723                 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
724         else
725                 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
726
727         new_create_timespec = smb_fname->st.st_ex_btime;
728
729         old_mode = dos_mode(conn, smb_fname);
730
731         if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
732                 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
733                         lret = SMB_VFS_SET_OFFLINE(conn, smb_fname);
734                         if (lret == -1) {
735                                 DEBUG(0, ("set_dos_mode: client has asked to "
736                                           "set FILE_ATTRIBUTE_OFFLINE to "
737                                           "%s/%s but there was an error while "
738                                           "setting it or it is not "
739                                           "supported.\n", parent_dir,
740                                           smb_fname_str_dbg(smb_fname)));
741                         }
742                 }
743         }
744
745         dosmode  &= ~FILE_ATTRIBUTE_OFFLINE;
746         old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
747
748         smb_fname->st.st_ex_btime = new_create_timespec;
749
750 #ifdef HAVE_STAT_DOS_FLAGS
751         {
752                 bool attributes_changed;
753
754                 if (set_stat_dos_flags(conn, smb_fname, dosmode,
755                                        &attributes_changed))
756                 {
757                         if (!newfile && attributes_changed) {
758                                 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
759                                     FILE_NOTIFY_CHANGE_ATTRIBUTES,
760                                     smb_fname->base_name);
761                         }
762                         smb_fname->st.st_ex_mode = unixmode;
763                         return 0;
764                 }
765         }
766 #endif
767         /* Store the DOS attributes in an EA by preference. */
768         if (set_ea_dos_attribute(conn, smb_fname, dosmode)) {
769                 if (!newfile) {
770                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
771                                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
772                                      smb_fname->base_name);
773                 }
774                 smb_fname->st.st_ex_mode = unixmode;
775                 return 0;
776         }
777
778         unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
779
780         /* preserve the s bits */
781         mask |= (S_ISUID | S_ISGID);
782
783         /* preserve the t bit */
784 #ifdef S_ISVTX
785         mask |= S_ISVTX;
786 #endif
787
788         /* possibly preserve the x bits */
789         if (!MAP_ARCHIVE(conn))
790                 mask |= S_IXUSR;
791         if (!MAP_SYSTEM(conn))
792                 mask |= S_IXGRP;
793         if (!MAP_HIDDEN(conn))
794                 mask |= S_IXOTH;
795
796         unixmode |= (smb_fname->st.st_ex_mode & mask);
797
798         /* if we previously had any r bits set then leave them alone */
799         if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
800                 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
801                 unixmode |= tmp;
802         }
803
804         /* if we previously had any w bits set then leave them alone 
805                 whilst adding in the new w bits, if the new mode is not rdonly */
806         if (!IS_DOS_READONLY(dosmode)) {
807                 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
808         }
809
810         /*
811          * From the chmod 2 man page:
812          *
813          * "If the calling process is not privileged, and the group of the file
814          * does not match the effective group ID of the process or one of its
815          * supplementary group IDs, the S_ISGID bit will be turned off, but
816          * this will not cause an error to be returned."
817          *
818          * Simply refuse to do the chmod in this case.
819          */
820
821         if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
822                         geteuid() != sec_initial_uid() &&
823                         !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
824                 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
825                         "set for directory %s\n",
826                         smb_fname_str_dbg(smb_fname)));
827                 errno = EPERM;
828                 return -1;
829         }
830
831         ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
832         if (ret == 0) {
833                 if(!newfile || (lret != -1)) {
834                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
835                                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
836                                      smb_fname->base_name);
837                 }
838                 smb_fname->st.st_ex_mode = unixmode;
839                 return 0;
840         }
841
842         if((errno != EPERM) && (errno != EACCES))
843                 return -1;
844
845         if(!lp_dos_filemode(SNUM(conn)))
846                 return -1;
847
848         /* We want DOS semantics, ie allow non owner with write permission to change the
849                 bits on a file. Just like file_ntimes below.
850         */
851
852         /* Check if we have write access. */
853         if (CAN_WRITE(conn)) {
854                 /*
855                  * We need to open the file with write access whilst
856                  * still in our current user context. This ensures we
857                  * are not violating security in doing the fchmod.
858                  */
859                 files_struct *fsp;
860                 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname,
861                                      &fsp)))
862                         return -1;
863                 become_root();
864                 ret = SMB_VFS_FCHMOD(fsp, unixmode);
865                 unbecome_root();
866                 close_file(NULL, fsp, NORMAL_CLOSE);
867                 if (!newfile) {
868                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
869                                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
870                                      smb_fname->base_name);
871                 }
872                 if (ret == 0) {
873                         smb_fname->st.st_ex_mode = unixmode;
874                 }
875         }
876
877         return( ret );
878 }
879
880
881 NTSTATUS file_set_sparse(connection_struct *conn,
882                          files_struct *fsp,
883                          bool sparse)
884 {
885         uint32_t old_dosmode;
886         uint32_t new_dosmode;
887         NTSTATUS status;
888
889         if (!CAN_WRITE(conn)) {
890                 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
891                         "on readonly share[%s]\n",
892                         smb_fname_str_dbg(fsp->fsp_name),
893                         sparse,
894                         lp_servicename(talloc_tos(), SNUM(conn))));
895                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
896         }
897
898         if (!(fsp->access_mask & FILE_WRITE_DATA) &&
899                         !(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
900                 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
901                         "access_mask[0x%08X] - access denied\n",
902                         smb_fname_str_dbg(fsp->fsp_name),
903                         sparse,
904                         fsp->access_mask));
905                 return NT_STATUS_ACCESS_DENIED;
906         }
907
908         DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
909                   sparse, smb_fname_str_dbg(fsp->fsp_name)));
910
911         if (!lp_store_dos_attributes(SNUM(conn))) {
912                 return NT_STATUS_INVALID_DEVICE_REQUEST;
913         }
914
915         status = vfs_stat_fsp(fsp);
916         if (!NT_STATUS_IS_OK(status)) {
917                 return status;
918         }
919
920         old_dosmode = dos_mode(conn, fsp->fsp_name);
921
922         if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
923                 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
924         } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
925                 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
926         } else {
927                 return NT_STATUS_OK;
928         }
929
930         /* Store the DOS attributes in an EA. */
931         if (!set_ea_dos_attribute(conn, fsp->fsp_name,
932                                   new_dosmode)) {
933                 if (errno == 0) {
934                         errno = EIO;
935                 }
936                 return map_nt_error_from_unix(errno);
937         }
938
939         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
940                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
941                      fsp->fsp_name->base_name);
942
943         fsp->is_sparse = sparse;
944
945         return NT_STATUS_OK;
946 }
947
948 /*******************************************************************
949  Wrapper around the VFS ntimes that possibly allows DOS semantics rather
950  than POSIX.
951 *******************************************************************/
952
953 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
954                 struct smb_file_time *ft)
955 {
956         int ret = -1;
957
958         errno = 0;
959
960         DEBUG(6, ("file_ntime: actime: %s",
961                   time_to_asc(convert_timespec_to_time_t(ft->atime))));
962         DEBUG(6, ("file_ntime: modtime: %s",
963                   time_to_asc(convert_timespec_to_time_t(ft->mtime))));
964         DEBUG(6, ("file_ntime: ctime: %s",
965                   time_to_asc(convert_timespec_to_time_t(ft->ctime))));
966         DEBUG(6, ("file_ntime: createtime: %s",
967                   time_to_asc(convert_timespec_to_time_t(ft->create_time))));
968
969         /* Don't update the time on read-only shares */
970         /* We need this as set_filetime (which can be called on
971            close and other paths) can end up calling this function
972            without the NEED_WRITE protection. Found by : 
973            Leo Weppelman <leo@wau.mis.ah.nl>
974         */
975
976         if (!CAN_WRITE(conn)) {
977                 return 0;
978         }
979
980         if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
981                 return 0;
982         }
983
984         if((errno != EPERM) && (errno != EACCES)) {
985                 return -1;
986         }
987
988         if(!lp_dos_filetimes(SNUM(conn))) {
989                 return -1;
990         }
991
992         /* We have permission (given by the Samba admin) to
993            break POSIX semantics and allow a user to change
994            the time on a file they don't own but can write to
995            (as DOS does).
996          */
997
998         /* Check if we have write access. */
999         if (can_write_to_file(conn, smb_fname)) {
1000                 /* We are allowed to become root and change the filetime. */
1001                 become_root();
1002                 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1003                 unbecome_root();
1004         }
1005
1006         return ret;
1007 }
1008
1009 /******************************************************************
1010  Force a "sticky" write time on a pathname. This will always be
1011  returned on all future write time queries and set on close.
1012 ******************************************************************/
1013
1014 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1015 {
1016         if (null_timespec(mtime)) {
1017                 return true;
1018         }
1019
1020         if (!set_sticky_write_time(fileid, mtime)) {
1021                 return false;
1022         }
1023
1024         return true;
1025 }
1026
1027 /******************************************************************
1028  Force a "sticky" write time on an fsp. This will always be
1029  returned on all future write time queries and set on close.
1030 ******************************************************************/
1031
1032 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1033 {
1034         if (null_timespec(mtime)) {
1035                 return true;
1036         }
1037
1038         fsp->write_time_forced = true;
1039         TALLOC_FREE(fsp->update_write_time_event);
1040
1041         return set_sticky_write_time_path(fsp->file_id, mtime);
1042 }
1043
1044 /******************************************************************
1045  Set a create time EA.
1046 ******************************************************************/
1047
1048 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1049                                 const struct smb_filename *psmb_fname,
1050                                 struct timespec create_time)
1051 {
1052         NTSTATUS status;
1053         struct smb_filename *smb_fname = NULL;
1054         uint32_t dosmode;
1055         int ret;
1056
1057         if (!lp_store_dos_attributes(SNUM(conn))) {
1058                 return NT_STATUS_OK;
1059         }
1060
1061         status = create_synthetic_smb_fname(talloc_tos(),
1062                                 psmb_fname->base_name,
1063                                 NULL, &psmb_fname->st,
1064                                 &smb_fname);
1065
1066         if (!NT_STATUS_IS_OK(status)) {
1067                 return status;
1068         }
1069
1070         dosmode = dos_mode(conn, smb_fname);
1071
1072         smb_fname->st.st_ex_btime = create_time;
1073
1074         ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1075         if (ret == -1) {
1076                 map_nt_error_from_unix(errno);
1077         }
1078
1079         DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1080                 smb_fname_str_dbg(smb_fname)));
1081
1082         return NT_STATUS_OK;
1083 }
1084
1085 /******************************************************************
1086  Return a create time.
1087 ******************************************************************/
1088
1089 struct timespec get_create_timespec(connection_struct *conn,
1090                                 struct files_struct *fsp,
1091                                 const struct smb_filename *smb_fname)
1092 {
1093         return smb_fname->st.st_ex_btime;
1094 }
1095
1096 /******************************************************************
1097  Return a change time (may look at EA in future).
1098 ******************************************************************/
1099
1100 struct timespec get_change_timespec(connection_struct *conn,
1101                                 struct files_struct *fsp,
1102                                 const struct smb_filename *smb_fname)
1103 {
1104         return smb_fname->st.st_ex_mtime;
1105 }