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