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