674a13076e1d98d4ed557fd631e4a5186235e574
[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 "globals.h"
23 #include "system/filesys.h"
24 #include "librpc/gen_ndr/ndr_xattr.h"
25 #include "librpc/gen_ndr/ioctl.h"
26 #include "../libcli/security/security.h"
27 #include "smbd/smbd.h"
28 #include "lib/param/loadparm.h"
29 #include "lib/util/tevent_ntstatus.h"
30 #include "lib/util/string_wrappers.h"
31 #include "fake_file.h"
32
33 static void dos_mode_debug_print(const char *func, uint32_t mode)
34 {
35         fstring modestr;
36
37         if (DEBUGLEVEL < DBGLVL_INFO) {
38                 return;
39         }
40
41         modestr[0] = '\0';
42
43         if (mode & FILE_ATTRIBUTE_HIDDEN) {
44                 fstrcat(modestr, "h");
45         }
46         if (mode & FILE_ATTRIBUTE_READONLY) {
47                 fstrcat(modestr, "r");
48         }
49         if (mode & FILE_ATTRIBUTE_SYSTEM) {
50                 fstrcat(modestr, "s");
51         }
52         if (mode & FILE_ATTRIBUTE_DIRECTORY) {
53                 fstrcat(modestr, "d");
54         }
55         if (mode & FILE_ATTRIBUTE_ARCHIVE) {
56                 fstrcat(modestr, "a");
57         }
58         if (mode & FILE_ATTRIBUTE_SPARSE) {
59                 fstrcat(modestr, "[sparse]");
60         }
61         if (mode & FILE_ATTRIBUTE_OFFLINE) {
62                 fstrcat(modestr, "[offline]");
63         }
64         if (mode & FILE_ATTRIBUTE_COMPRESSED) {
65                 fstrcat(modestr, "[compressed]");
66         }
67
68         DBG_INFO("%s returning (0x%x): \"%s\"\n", func, (unsigned)mode,
69                  modestr);
70 }
71
72 static uint32_t filter_mode_by_protocol(enum protocol_types protocol,
73                                         uint32_t mode)
74 {
75         if (protocol <= PROTOCOL_LANMAN2) {
76                 DEBUG(10,("filter_mode_by_protocol: "
77                         "filtering result 0x%x to 0x%x\n",
78                         (unsigned int)mode,
79                         (unsigned int)(mode & 0x3f) ));
80                 mode &= 0x3f;
81         }
82         return mode;
83 }
84
85 /****************************************************************************
86  Change a dos mode to a unix mode.
87     Base permission for files:
88          if creating file and inheriting (i.e. parent_dir != NULL)
89            apply read/write bits from parent directory.
90          else
91            everybody gets read bit set
92          dos readonly is represented in unix by removing everyone's write bit
93          dos archive is represented in unix by the user's execute bit
94          dos system is represented in unix by the group's execute bit
95          dos hidden is represented in unix by the other's execute bit
96          if !inheriting {
97            Then apply create mask,
98            then add force bits.
99          }
100     Base permission for directories:
101          dos directory is represented in unix by unix's dir bit and the exec bit
102          if !inheriting {
103            Then apply create mask,
104            then add force bits.
105          }
106 ****************************************************************************/
107
108 mode_t unix_mode(connection_struct *conn, int dosmode,
109                  const struct smb_filename *smb_fname,
110                  struct files_struct *parent_dirfsp)
111 {
112         mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
113         mode_t dir_mode = 0; /* Mode of the inherit_from directory if
114                               * inheriting. */
115
116         if ((dosmode & FILE_ATTRIBUTE_READONLY) &&
117             !lp_store_dos_attributes(SNUM(conn))) {
118                 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
119         }
120
121         if ((parent_dirfsp != NULL) && lp_inherit_permissions(SNUM(conn))) {
122                 struct stat_ex sbuf = { .st_ex_nlink = 0, };
123                 int ret;
124
125                 DBG_DEBUG("[%s] inheriting from [%s]\n",
126                           smb_fname_str_dbg(smb_fname),
127                           smb_fname_str_dbg(parent_dirfsp->fsp_name));
128
129                 ret = SMB_VFS_FSTAT(parent_dirfsp, &sbuf);
130                 if (ret != 0) {
131                         DBG_ERR("fstat failed [%s]: %s\n",
132                                 smb_fname_str_dbg(parent_dirfsp->fsp_name),
133                                 strerror(errno));
134                         return(0);      /* *** shouldn't happen! *** */
135                 }
136
137                 /* Save for later - but explicitly remove setuid bit for safety. */
138                 dir_mode = sbuf.st_ex_mode & ~S_ISUID;
139                 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
140                          smb_fname_str_dbg(smb_fname), (int)dir_mode));
141                 /* Clear "result" */
142                 result = 0;
143         }
144
145         if (dosmode & FILE_ATTRIBUTE_DIRECTORY) {
146                 /* We never make directories read only for the owner as under DOS a user
147                 can always create a file in a read-only directory. */
148                 result |= (S_IFDIR | S_IWUSR);
149
150                 if (dir_mode) {
151                         /* Inherit mode of parent directory. */
152                         result |= dir_mode;
153                 } else {
154                         /* Provisionally add all 'x' bits */
155                         result |= (S_IXUSR | S_IXGRP | S_IXOTH);
156
157                         /* Apply directory mask */
158                         result &= lp_directory_mask(SNUM(conn));
159                         /* Add in force bits */
160                         result |= lp_force_directory_mode(SNUM(conn));
161                 }
162         } else {
163                 if ((dosmode & FILE_ATTRIBUTE_ARCHIVE) &&
164                     lp_map_archive(SNUM(conn))) {
165                         result |= S_IXUSR;
166                 }
167
168                 if ((dosmode & FILE_ATTRIBUTE_SYSTEM) &&
169                     lp_map_system(SNUM(conn))) {
170                         result |= S_IXGRP;
171                 }
172
173                 if ((dosmode & FILE_ATTRIBUTE_HIDDEN) &&
174                     lp_map_hidden(SNUM(conn))) {
175                         result |= S_IXOTH;
176                 }
177
178                 if (dir_mode) {
179                         /* Inherit 666 component of parent directory mode */
180                         result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
181                 } else {
182                         /* Apply mode mask */
183                         result &= lp_create_mask(SNUM(conn));
184                         /* Add in force bits */
185                         result |= lp_force_create_mode(SNUM(conn));
186                 }
187         }
188
189         DBG_INFO("unix_mode(%s) returning 0%o\n",
190                  smb_fname_str_dbg(smb_fname), (int)result);
191
192         return(result);
193 }
194
195 /****************************************************************************
196  Change a unix mode to a dos mode.
197 ****************************************************************************/
198
199 static uint32_t dos_mode_from_sbuf(connection_struct *conn,
200                                    const struct stat_ex *st,
201                                    struct files_struct *fsp)
202 {
203         int result = 0;
204         enum mapreadonly_options ro_opts =
205                 (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
206
207 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
208         /* if we can find out if a file is immutable we should report it r/o */
209         if (st->st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
210                 result |= FILE_ATTRIBUTE_READONLY;
211         }
212 #endif
213         if (ro_opts == MAP_READONLY_YES) {
214                 /* Original Samba method - map inverse of user "w" bit. */
215                 if ((st->st_ex_mode & S_IWUSR) == 0) {
216                         result |= FILE_ATTRIBUTE_READONLY;
217                 }
218         } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
219                 /* smb_fname->fsp can be NULL for an MS-DFS link. */
220                 /* Check actual permissions for read-only. */
221                 if ((fsp != NULL) && !can_write_to_fsp(fsp)) {
222                         result |= FILE_ATTRIBUTE_READONLY;
223                 }
224         } /* Else never set the readonly bit. */
225
226         if (MAP_ARCHIVE(conn) && ((st->st_ex_mode & S_IXUSR) != 0)) {
227                 result |= FILE_ATTRIBUTE_ARCHIVE;
228         }
229
230         if (MAP_SYSTEM(conn) && ((st->st_ex_mode & S_IXGRP) != 0)) {
231                 result |= FILE_ATTRIBUTE_SYSTEM;
232         }
233
234         if (MAP_HIDDEN(conn) && ((st->st_ex_mode & S_IXOTH) != 0)) {
235                 result |= FILE_ATTRIBUTE_HIDDEN;
236         }
237
238         if (S_ISDIR(st->st_ex_mode)) {
239                 result = FILE_ATTRIBUTE_DIRECTORY |
240                          (result & FILE_ATTRIBUTE_READONLY);
241         }
242
243         dos_mode_debug_print(__func__, result);
244
245         return result;
246 }
247
248 /****************************************************************************
249  Get DOS attributes from an EA.
250  This can also pull the create time into the stat struct inside smb_fname.
251 ****************************************************************************/
252
253 NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
254                                   DATA_BLOB blob,
255                                   uint32_t *pattr)
256 {
257         struct xattr_DOSATTRIB dosattrib;
258         enum ndr_err_code ndr_err;
259         uint32_t dosattr;
260
261         ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
262                         (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
263
264         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
265                 DBG_WARNING("bad ndr decode "
266                             "from EA on file %s: Error = %s\n",
267                             smb_fname_str_dbg(smb_fname),
268                             ndr_errstr(ndr_err));
269                 return ndr_map_error2ntstatus(ndr_err);
270         }
271
272         DBG_DEBUG("%s attr = %s\n",
273                   smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex);
274
275         switch (dosattrib.version) {
276         case 0xFFFF:
277                 dosattr = dosattrib.info.compatinfoFFFF.attrib;
278                 break;
279         case 1:
280                 dosattr = dosattrib.info.info1.attrib;
281                 if (!null_nttime(dosattrib.info.info1.create_time)) {
282                         struct timespec create_time =
283                                 nt_time_to_unix_timespec(
284                                         dosattrib.info.info1.create_time);
285
286                         update_stat_ex_create_time(&smb_fname->st,
287                                                    create_time);
288
289                         DBG_DEBUG("file %s case 1 set btime %s",
290                                   smb_fname_str_dbg(smb_fname),
291                                   time_to_asc(convert_timespec_to_time_t(
292                                                       create_time)));
293                 }
294                 break;
295         case 2:
296                 dosattr = dosattrib.info.oldinfo2.attrib;
297                 /* Don't know what flags to check for this case. */
298                 break;
299         case 3:
300                 dosattr = dosattrib.info.info3.attrib;
301                 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
302                     !null_nttime(dosattrib.info.info3.create_time)) {
303                         struct timespec create_time =
304                                 nt_time_to_full_timespec(
305                                         dosattrib.info.info3.create_time);
306
307                         update_stat_ex_create_time(&smb_fname->st,
308                                                    create_time);
309
310                         DBG_DEBUG("file %s case 3 set btime %s",
311                                   smb_fname_str_dbg(smb_fname),
312                                   time_to_asc(convert_timespec_to_time_t(
313                                                       create_time)));
314                 }
315                 break;
316         case 4:
317         case 5:
318         {
319                 uint32_t info_valid_flags;
320                 NTTIME info_create_time;
321
322                 if (dosattrib.version == 4) {
323                         info_valid_flags = dosattrib.info.info4.valid_flags;
324                         info_create_time = dosattrib.info.info4.create_time;
325                         dosattr = dosattrib.info.info4.attrib;
326                 } else {
327                         info_valid_flags = dosattrib.info.info5.valid_flags;
328                         info_create_time = dosattrib.info.info5.create_time;
329                         dosattr = dosattrib.info.info5.attrib;
330                 }
331
332                 if ((info_valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
333                     !null_nttime(info_create_time))
334                 {
335                         struct timespec creat_time;
336
337                         creat_time = nt_time_to_full_timespec(info_create_time);
338                         update_stat_ex_create_time(&smb_fname->st, creat_time);
339
340                         DBG_DEBUG("file [%s] creation time [%s]\n",
341                                 smb_fname_str_dbg(smb_fname),
342                                 nt_time_string(talloc_tos(), info_create_time));
343                 }
344
345                 break;
346         }
347         default:
348                 DBG_WARNING("Badly formed DOSATTRIB on file %s - %s\n",
349                             smb_fname_str_dbg(smb_fname), blob.data);
350                 /* Should this be INTERNAL_ERROR? */
351                 return NT_STATUS_INVALID_PARAMETER;
352         }
353
354         if (S_ISDIR(smb_fname->st.st_ex_mode)) {
355                 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
356         }
357
358         /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
359         *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
360
361         dos_mode_debug_print(__func__, *pattr);
362
363         return NT_STATUS_OK;
364 }
365
366 NTSTATUS fget_ea_dos_attribute(struct files_struct *fsp,
367                               uint32_t *pattr)
368 {
369         DATA_BLOB blob;
370         ssize_t sizeret;
371         fstring attrstr;
372         NTSTATUS status;
373
374         if (!lp_store_dos_attributes(SNUM(fsp->conn))) {
375                 return NT_STATUS_NOT_IMPLEMENTED;
376         }
377
378         /* Don't reset pattr to zero as we may already have filename-based attributes we
379            need to preserve. */
380
381         sizeret = SMB_VFS_FGETXATTR(fsp,
382                                     SAMBA_XATTR_DOS_ATTRIB,
383                                     attrstr,
384                                     sizeof(attrstr));
385         if (sizeret == -1 && ( errno == EPERM || errno == EACCES )) {
386                 /* we may also retrieve dos attribs for unreadable files, this
387                    is why we'll retry as root. We don't use root in the first
388                    run because in cases like NFS, root might have even less
389                    rights than the real user
390                 */
391                 become_root();
392                 sizeret = SMB_VFS_FGETXATTR(fsp,
393                                             SAMBA_XATTR_DOS_ATTRIB,
394                                             attrstr,
395                                             sizeof(attrstr));
396                 unbecome_root();
397         }
398         if (sizeret == -1) {
399                 DBG_INFO("Cannot get attribute "
400                          "from EA on file %s: Error = %s\n",
401                          fsp_str_dbg(fsp), strerror(errno));
402                 return map_nt_error_from_unix(errno);
403         }
404
405         blob.data = (uint8_t *)attrstr;
406         blob.length = sizeret;
407
408         status = parse_dos_attribute_blob(fsp->fsp_name, blob, pattr);
409         if (!NT_STATUS_IS_OK(status)) {
410                 return status;
411         }
412
413         return NT_STATUS_OK;
414 }
415
416 /****************************************************************************
417  Set DOS attributes in an EA.
418  Also sets the create time.
419 ****************************************************************************/
420
421 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
422                               struct smb_filename *smb_fname,
423                               uint32_t dosmode)
424 {
425         struct xattr_DOSATTRIB dosattrib = { .version = 0, };
426         enum ndr_err_code ndr_err;
427         DATA_BLOB blob = { .data = NULL, };
428         struct timespec btime;
429         int ret;
430
431         if (!lp_store_dos_attributes(SNUM(conn))) {
432                 return NT_STATUS_NOT_IMPLEMENTED;
433         }
434
435         if (smb_fname->fsp == NULL) {
436                 /* symlink */
437                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
438         }
439         /*
440          * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in
441          * vfs_default via DMAPI if that is enabled.
442          */
443         dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
444
445         dosattrib.version = 5;
446         dosattrib.info.info5.valid_flags = XATTR_DOSINFO_ATTRIB |
447                                         XATTR_DOSINFO_CREATE_TIME;
448         dosattrib.info.info5.attrib = dosmode;
449         dosattrib.info.info5.create_time = full_timespec_to_nt_time(
450                 &smb_fname->st.st_ex_btime);
451
452         DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
453                 (unsigned int)dosmode,
454                 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
455                 smb_fname_str_dbg(smb_fname) ));
456
457         ndr_err = ndr_push_struct_blob(
458                         &blob, talloc_tos(), &dosattrib,
459                         (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
460
461         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
462                 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
463                         ndr_errstr(ndr_err)));
464                 return ndr_map_error2ntstatus(ndr_err);
465         }
466
467         if (blob.data == NULL || blob.length == 0) {
468                 /* Should this be INTERNAL_ERROR? */
469                 return NT_STATUS_INVALID_PARAMETER;
470         }
471
472         ret = SMB_VFS_FSETXATTR(smb_fname->fsp,
473                                SAMBA_XATTR_DOS_ATTRIB,
474                                blob.data, blob.length, 0);
475         if (ret != 0) {
476                 NTSTATUS status = NT_STATUS_OK;
477                 bool set_dosmode_ok = false;
478
479                 if ((errno != EPERM) && (errno != EACCES)) {
480                         DBG_INFO("Cannot set "
481                                  "attribute EA on file %s: Error = %s\n",
482                                  smb_fname_str_dbg(smb_fname), strerror(errno));
483                         return map_nt_error_from_unix(errno);
484                 }
485
486                 /* We want DOS semantics, ie allow non owner with write permission to change the
487                         bits on a file. Just like file_ntimes below.
488                 */
489
490                 /* Check if we have write access. */
491                 if (!CAN_WRITE(conn)) {
492                         return NT_STATUS_ACCESS_DENIED;
493                 }
494
495                 status = smbd_check_access_rights_fsp(conn->cwd_fsp,
496                                         smb_fname->fsp,
497                                         false,
498                                         FILE_WRITE_ATTRIBUTES);
499                 if (NT_STATUS_IS_OK(status)) {
500                         set_dosmode_ok = true;
501                 }
502
503                 if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
504                         set_dosmode_ok = can_write_to_fsp(smb_fname->fsp);
505                 }
506
507                 if (!set_dosmode_ok) {
508                         return NT_STATUS_ACCESS_DENIED;
509                 }
510
511                 become_root();
512                 ret = SMB_VFS_FSETXATTR(smb_fname->fsp,
513                                         SAMBA_XATTR_DOS_ATTRIB,
514                                         blob.data, blob.length, 0);
515                 if (ret == 0) {
516                         status = NT_STATUS_OK;
517                 }
518                 unbecome_root();
519                 if (!NT_STATUS_IS_OK(status)) {
520                         return status;
521                 }
522         }
523
524         /*
525          * We correctly stored the create time.
526          * We *always* set XATTR_DOSINFO_CREATE_TIME,
527          * so now it can no longer be considered
528          * calculated. Make sure to use the value rounded
529          * to NTTIME granularity we've stored in the xattr.
530          */
531         btime = nt_time_to_full_timespec(dosattrib.info.info5.create_time);
532         update_stat_ex_create_time(&smb_fname->st, btime);
533
534         DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
535                 (unsigned int)dosmode,
536                 smb_fname_str_dbg(smb_fname)));
537         return NT_STATUS_OK;
538 }
539
540 static uint32_t
541 dos_mode_from_name(connection_struct *conn, const char *name, uint32_t dosmode)
542 {
543         const char *p = NULL;
544         uint32_t result = dosmode;
545
546         if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
547             lp_hide_dot_files(SNUM(conn)))
548         {
549                 p = strrchr_m(name, '/');
550                 if (p) {
551                         p++;
552                 } else {
553                         p = name;
554                 }
555
556                 /* Only . and .. are not hidden. */
557                 if ((p[0] == '.') && !(ISDOT(p) || ISDOTDOT(p))) {
558                         result |= FILE_ATTRIBUTE_HIDDEN;
559                 }
560         }
561
562         if (!(result & FILE_ATTRIBUTE_HIDDEN) && IS_HIDDEN_PATH(conn, name)) {
563                 result |= FILE_ATTRIBUTE_HIDDEN;
564         }
565
566         return result;
567 }
568
569 /****************************************************************************
570  Change a unix mode to a dos mode for an ms dfs link.
571 ****************************************************************************/
572
573 uint32_t dos_mode_msdfs(connection_struct *conn,
574                         const char *name,
575                         const struct stat_ex *st)
576 {
577         uint32_t result = 0;
578
579         DEBUG(8, ("dos_mode_msdfs: %s\n", name));
580
581         if (!VALID_STAT(*st)) {
582                 return 0;
583         }
584
585         result = dos_mode_from_name(conn, name, result);
586         result |= dos_mode_from_sbuf(conn, st, NULL);
587
588         if (result == 0) {
589                 result = FILE_ATTRIBUTE_NORMAL;
590         }
591
592         result = filter_mode_by_protocol(conn_protocol(conn->sconn), result);
593
594         /*
595          * Add in that it is a reparse point
596          */
597         result |= FILE_ATTRIBUTE_REPARSE_POINT;
598
599         dos_mode_debug_print(__func__, result);
600
601         return(result);
602 }
603
604 /*
605  * check whether a file or directory is flagged as compressed.
606  */
607 static NTSTATUS dos_mode_check_compressed(struct files_struct *fsp,
608                                           bool *is_compressed)
609 {
610         NTSTATUS status;
611         uint16_t compression_fmt;
612
613         status = SMB_VFS_FGET_COMPRESSION(
614                 fsp->conn, talloc_tos(), fsp, &compression_fmt);
615         if (!NT_STATUS_IS_OK(status)) {
616                 return status;
617         }
618
619         if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
620                 *is_compressed = true;
621         } else {
622                 *is_compressed = false;
623         }
624         return NT_STATUS_OK;
625 }
626
627 static uint32_t dos_mode_post(uint32_t dosmode,
628                               struct files_struct *fsp,
629                               const char *func)
630 {
631         struct smb_filename *smb_fname = NULL;
632         NTSTATUS status;
633
634         if (fsp != NULL) {
635                 smb_fname = fsp->fsp_name;
636         }
637         SMB_ASSERT(smb_fname != NULL);
638
639         /*
640          * According to MS-FSA a stream name does not have
641          * separate DOS attribute metadata, so we must return
642          * the DOS attribute from the base filename. With one caveat,
643          * a non-default stream name can never be a directory.
644          *
645          * As this is common to all streams data stores, we handle
646          * it here instead of inside all stream VFS modules.
647          *
648          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
649          */
650
651         if (is_named_stream(smb_fname)) {
652                 /* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
653                 dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
654         }
655
656         if (fsp->conn->fs_capabilities & FILE_FILE_COMPRESSION) {
657                 bool compressed = false;
658
659                 status = dos_mode_check_compressed(fsp, &compressed);
660                 if (NT_STATUS_IS_OK(status) && compressed) {
661                         dosmode |= FILE_ATTRIBUTE_COMPRESSED;
662                 }
663         }
664
665         dosmode |= dos_mode_from_name(fsp->conn, smb_fname->base_name, dosmode);
666
667         if (S_ISDIR(smb_fname->st.st_ex_mode)) {
668                 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
669         } else if (dosmode == 0) {
670                 dosmode = FILE_ATTRIBUTE_NORMAL;
671         }
672
673         dosmode = filter_mode_by_protocol(conn_protocol(fsp->conn->sconn),
674                                           dosmode);
675
676         dos_mode_debug_print(func, dosmode);
677         return dosmode;
678 }
679
680 /****************************************************************************
681  Change a unix mode to a dos mode.
682  May also read the create timespec into the stat struct in smb_fname
683  if "store dos attributes" is true.
684 ****************************************************************************/
685
686 uint32_t fdos_mode(struct files_struct *fsp)
687 {
688         uint32_t result = 0;
689         NTSTATUS status = NT_STATUS_OK;
690
691         DBG_DEBUG("%s\n", fsp_str_dbg(fsp));
692
693         if (fsp->fake_file_handle != NULL) {
694                 return dosmode_from_fake_filehandle(fsp->fake_file_handle);
695         }
696
697         if (!VALID_STAT(fsp->fsp_name->st)) {
698                 return 0;
699         }
700
701         if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
702                 return FILE_ATTRIBUTE_NORMAL;
703         }
704
705         if (fsp->fsp_name->st.cached_dos_attributes != FILE_ATTRIBUTE_INVALID) {
706                 return fsp->fsp_name->st.cached_dos_attributes;
707         }
708
709         /* Get the DOS attributes via the VFS if we can */
710         status = SMB_VFS_FGET_DOS_ATTRIBUTES(fsp->conn,
711                                              metadata_fsp(fsp),
712                                              &result);
713         if (!NT_STATUS_IS_OK(status)) {
714                 /*
715                  * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
716                  */
717                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
718                         result |= dos_mode_from_sbuf(fsp->conn,
719                                                      &fsp->fsp_name->st,
720                                                      fsp);
721                 }
722         }
723
724         fsp->fsp_name->st.cached_dos_attributes = dos_mode_post(result, fsp, __func__);
725         return fsp->fsp_name->st.cached_dos_attributes;
726 }
727
728 struct dos_mode_at_state {
729         files_struct *dir_fsp;
730         struct smb_filename *smb_fname;
731         uint32_t dosmode;
732 };
733
734 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq);
735
736 struct tevent_req *dos_mode_at_send(TALLOC_CTX *mem_ctx,
737                                     struct tevent_context *ev,
738                                     files_struct *dir_fsp,
739                                     struct smb_filename *smb_fname)
740 {
741         struct tevent_req *req = NULL;
742         struct dos_mode_at_state *state = NULL;
743         struct tevent_req *subreq = NULL;
744
745         DBG_DEBUG("%s\n", smb_fname_str_dbg(smb_fname));
746
747         req = tevent_req_create(mem_ctx, &state,
748                                 struct dos_mode_at_state);
749         if (req == NULL) {
750                 return NULL;
751         }
752
753         *state = (struct dos_mode_at_state) {
754                 .dir_fsp = dir_fsp,
755                 .smb_fname = smb_fname,
756         };
757
758         if (!VALID_STAT(smb_fname->st)) {
759                 tevent_req_done(req);
760                 return tevent_req_post(req, ev);
761         }
762
763         if (smb_fname->fsp == NULL) {
764                 if (ISDOTDOT(smb_fname->base_name)) {
765                         /*
766                          * smb_fname->fsp is explicitly closed
767                          * for ".." to prevent meta-data leakage.
768                          */
769                         state->dosmode = FILE_ATTRIBUTE_DIRECTORY;
770                 } else {
771                         /*
772                          * This is a symlink in POSIX context.
773                          * FIXME ? Should we move to returning
774                          * FILE_ATTRIBUTE_REPARSE_POINT here ?
775                          */
776                         state->dosmode = FILE_ATTRIBUTE_NORMAL;
777                 }
778                 tevent_req_done(req);
779                 return tevent_req_post(req, ev);
780         }
781
782         subreq = SMB_VFS_GET_DOS_ATTRIBUTES_SEND(state,
783                                                  ev,
784                                                  dir_fsp,
785                                                  smb_fname);
786         if (tevent_req_nomem(subreq, req)) {
787                 return tevent_req_post(req, ev);
788         }
789         tevent_req_set_callback(subreq, dos_mode_at_vfs_get_dosmode_done, req);
790
791         return req;
792 }
793
794 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
795 {
796         struct tevent_req *req =
797                 tevent_req_callback_data(subreq,
798                 struct tevent_req);
799         struct dos_mode_at_state *state =
800                 tevent_req_data(req,
801                 struct dos_mode_at_state);
802         struct vfs_aio_state aio_state;
803         NTSTATUS status;
804         bool ok;
805
806         /*
807          * Make sure we run as the user again
808          */
809         ok = change_to_user_and_service_by_fsp(state->dir_fsp);
810         SMB_ASSERT(ok);
811
812         status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV(subreq,
813                                                  &aio_state,
814                                                  &state->dosmode);
815         TALLOC_FREE(subreq);
816         if (!NT_STATUS_IS_OK(status)) {
817                 /*
818                  * Both the sync dos_mode() as well as the async
819                  * dos_mode_at_[send|recv] have no real error return, the only
820                  * unhandled error is when the stat info in smb_fname is not
821                  * valid (cf the checks in dos_mode() and dos_mode_at_send().
822                  *
823                  * If SMB_VFS_GET_DOS_ATTRIBUTES[_SEND|_RECV] fails we must call
824                  * dos_mode_post() which also does the mapping of a last resort
825                  * from S_IFMT(st_mode).
826                  *
827                  * Only if we get NT_STATUS_NOT_IMPLEMENTED or
828                  * NT_STATUS_NOT_SUPPORTED from a stacked VFS module we must
829                  * fallback to sync processing.
830                  */
831                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) &&
832                     !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED))
833                 {
834                         /*
835                          * state->dosmode should still be 0, but reset
836                          * it to be sure.
837                          */
838                         state->dosmode = 0;
839                         status = NT_STATUS_OK;
840                 }
841         }
842         if (NT_STATUS_IS_OK(status)) {
843                 state->dosmode = dos_mode_post(state->dosmode,
844                                                state->smb_fname->fsp,
845                                                __func__);
846                 tevent_req_done(req);
847                 return;
848         }
849
850         /*
851          * Fall back to sync dos_mode() if we got NOT_IMPLEMENTED.
852          */
853
854         state->dosmode = fdos_mode(state->smb_fname->fsp);
855         tevent_req_done(req);
856         return;
857 }
858
859 NTSTATUS dos_mode_at_recv(struct tevent_req *req, uint32_t *dosmode)
860 {
861         struct dos_mode_at_state *state =
862                 tevent_req_data(req,
863                 struct dos_mode_at_state);
864         NTSTATUS status;
865
866         if (tevent_req_is_nterror(req, &status)) {
867                 tevent_req_received(req);
868                 return status;
869         }
870
871         *dosmode = state->dosmode;
872         tevent_req_received(req);
873         return NT_STATUS_OK;
874 }
875
876 /*******************************************************************
877  chmod a file - but preserve some bits.
878  If "store dos attributes" is also set it will store the create time
879  from the stat struct in smb_fname (in NTTIME format) in the EA
880  attribute also.
881 ********************************************************************/
882
883 int file_set_dosmode(connection_struct *conn,
884                      struct smb_filename *smb_fname,
885                      uint32_t dosmode,
886                      struct smb_filename *parent_dir,
887                      bool newfile)
888 {
889         int mask=0;
890         mode_t tmp;
891         mode_t unixmode;
892         int ret = -1;
893         NTSTATUS status;
894
895         if (!CAN_WRITE(conn)) {
896                 errno = EROFS;
897                 return -1;
898         }
899
900         if (S_ISLNK(smb_fname->st.st_ex_mode)) {
901                 /* A symlink in POSIX context, ignore */
902                 return 0;
903         }
904
905         if ((S_ISDIR(smb_fname->st.st_ex_mode)) &&
906             (dosmode & FILE_ATTRIBUTE_TEMPORARY))
907         {
908                 errno = EINVAL;
909                 return -1;
910         }
911
912         dosmode &= SAMBA_ATTRIBUTES_MASK;
913
914         DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
915                   dosmode, smb_fname_str_dbg(smb_fname)));
916
917         if (smb_fname->fsp == NULL) {
918                 errno = ENOENT;
919                 return -1;
920         }
921
922         if ((smb_fname->fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
923             !lp_store_dos_attributes(SNUM(conn)))
924         {
925                 return 0;
926         }
927
928         unixmode = smb_fname->st.st_ex_mode;
929
930         get_acl_group_bits(conn, smb_fname->fsp, &smb_fname->st.st_ex_mode);
931
932         if (S_ISDIR(smb_fname->st.st_ex_mode))
933                 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
934         else
935                 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
936
937         /* Store the DOS attributes in an EA by preference. */
938         status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn,
939                                              metadata_fsp(smb_fname->fsp),
940                                              dosmode);
941         if (NT_STATUS_IS_OK(status)) {
942                 smb_fname->st.cached_dos_attributes = dosmode;
943                 ret = 0;
944                 goto done;
945         }
946
947         /*
948          * Only fall back to using UNIX modes if
949          * we get NOT_IMPLEMENTED.
950          */
951         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
952                 errno = map_errno_from_nt_status(status);
953                 return -1;
954         }
955
956         /* Fall back to UNIX modes. */
957         unixmode = unix_mode(
958                 conn,
959                 dosmode,
960                 smb_fname,
961                 parent_dir != NULL ? parent_dir->fsp : NULL);
962
963         /* preserve the file type bits */
964         mask |= S_IFMT;
965
966         /* preserve the s bits */
967         mask |= (S_ISUID | S_ISGID);
968
969         /* preserve the t bit */
970 #ifdef S_ISVTX
971         mask |= S_ISVTX;
972 #endif
973
974         /* possibly preserve the x bits */
975         if (!MAP_ARCHIVE(conn))
976                 mask |= S_IXUSR;
977         if (!MAP_SYSTEM(conn))
978                 mask |= S_IXGRP;
979         if (!MAP_HIDDEN(conn))
980                 mask |= S_IXOTH;
981
982         unixmode |= (smb_fname->st.st_ex_mode & mask);
983
984         /* if we previously had any r bits set then leave them alone */
985         if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
986                 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
987                 unixmode |= tmp;
988         }
989
990         /* if we previously had any w bits set then leave them alone
991                 whilst adding in the new w bits, if the new mode is not rdonly */
992         if (!(dosmode & FILE_ATTRIBUTE_READONLY)) {
993                 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
994         }
995
996         /*
997          * From the chmod 2 man page:
998          *
999          * "If the calling process is not privileged, and the group of the file
1000          * does not match the effective group ID of the process or one of its
1001          * supplementary group IDs, the S_ISGID bit will be turned off, but
1002          * this will not cause an error to be returned."
1003          *
1004          * Simply refuse to do the chmod in this case.
1005          */
1006
1007         if (S_ISDIR(smb_fname->st.st_ex_mode) &&
1008             (unixmode & S_ISGID) &&
1009             geteuid() != sec_initial_uid() &&
1010             !current_user_in_group(conn, smb_fname->st.st_ex_gid))
1011         {
1012                 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
1013                         "set for directory %s\n",
1014                         smb_fname_str_dbg(smb_fname)));
1015                 errno = EPERM;
1016                 return -1;
1017         }
1018
1019         ret = SMB_VFS_FCHMOD(smb_fname->fsp, unixmode);
1020         if (ret == 0) {
1021                 goto done;
1022         }
1023
1024         if((errno != EPERM) && (errno != EACCES))
1025                 return -1;
1026
1027         if(!lp_dos_filemode(SNUM(conn)))
1028                 return -1;
1029
1030         /* We want DOS semantics, ie allow non owner with write permission to change the
1031                 bits on a file. Just like file_ntimes below.
1032         */
1033
1034         if (!can_write_to_fsp(smb_fname->fsp))
1035         {
1036                 errno = EACCES;
1037                 return -1;
1038         }
1039
1040         become_root();
1041         ret = SMB_VFS_FCHMOD(smb_fname->fsp, unixmode);
1042         unbecome_root();
1043
1044 done:
1045         if (!newfile) {
1046                 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1047                              FILE_NOTIFY_CHANGE_ATTRIBUTES,
1048                              smb_fname->base_name);
1049         }
1050         if (ret == 0) {
1051                 smb_fname->st.st_ex_mode = unixmode;
1052         }
1053
1054         return( ret );
1055 }
1056
1057
1058 NTSTATUS file_set_sparse(connection_struct *conn,
1059                          files_struct *fsp,
1060                          bool sparse)
1061 {
1062         const struct loadparm_substitution *lp_sub =
1063                 loadparm_s3_global_substitution();
1064         uint32_t old_dosmode;
1065         uint32_t new_dosmode;
1066         NTSTATUS status;
1067
1068         if (!CAN_WRITE(conn)) {
1069                 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1070                         "on readonly share[%s]\n",
1071                         smb_fname_str_dbg(fsp->fsp_name),
1072                         sparse,
1073                         lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1074                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1075         }
1076
1077         /*
1078          * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
1079          * following access flags are granted.
1080          */
1081         status = check_any_access_fsp(fsp,
1082                                   FILE_WRITE_DATA
1083                                   | FILE_WRITE_ATTRIBUTES
1084                                   | SEC_FILE_APPEND_DATA);
1085         if (!NT_STATUS_IS_OK(status)) {
1086                 DBG_DEBUG("fname[%s] set[%u] "
1087                           "access_mask[0x%08X] - access denied\n",
1088                           smb_fname_str_dbg(fsp->fsp_name),
1089                           sparse,
1090                           fsp->access_mask);
1091                 return status;
1092         }
1093
1094         if (fsp->fsp_flags.is_directory) {
1095                 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
1096                           (sparse ? "set" : "clear"),
1097                           smb_fname_str_dbg(fsp->fsp_name)));
1098                 return NT_STATUS_INVALID_PARAMETER;
1099         }
1100
1101         if (IS_IPC(conn) || IS_PRINT(conn)) {
1102                 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
1103                           (sparse ? "set" : "clear")));
1104                 return NT_STATUS_INVALID_PARAMETER;
1105         }
1106
1107         if (fsp_is_alternate_stream(fsp)) {
1108                 /*
1109                  * MS-FSA 2.1.1.5 IsSparse
1110                  *
1111                  * This is a per stream attribute, but our backends don't
1112                  * support it a consistent way, therefore just pretend
1113                  * success and ignore the request.
1114                  */
1115                 DBG_DEBUG("Ignoring request to set FILE_ATTRIBUTE_SPARSE on "
1116                           "[%s]\n", fsp_str_dbg(fsp));
1117                 return NT_STATUS_OK;
1118         }
1119
1120         DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
1121                   sparse, smb_fname_str_dbg(fsp->fsp_name)));
1122
1123         if (!lp_store_dos_attributes(SNUM(conn))) {
1124                 return NT_STATUS_INVALID_DEVICE_REQUEST;
1125         }
1126
1127         status = vfs_stat_fsp(fsp);
1128         if (!NT_STATUS_IS_OK(status)) {
1129                 return status;
1130         }
1131
1132         old_dosmode = fdos_mode(fsp);
1133
1134         if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1135                 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
1136         } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1137                 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
1138         } else {
1139                 return NT_STATUS_OK;
1140         }
1141
1142         /* Store the DOS attributes in an EA. */
1143         status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
1144         if (!NT_STATUS_IS_OK(status)) {
1145                 return status;
1146         }
1147
1148         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1149                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
1150                      fsp->fsp_name->base_name);
1151
1152         fsp->fsp_name->st.cached_dos_attributes = new_dosmode;
1153         fsp->fsp_flags.is_sparse = sparse;
1154
1155         return NT_STATUS_OK;
1156 }
1157
1158 /*******************************************************************
1159  Wrapper around the VFS ntimes that possibly allows DOS semantics rather
1160  than POSIX.
1161 *******************************************************************/
1162
1163 int file_ntimes(connection_struct *conn,
1164                 files_struct *fsp,
1165                 struct smb_file_time *ft)
1166 {
1167         int ret = -1;
1168
1169         errno = 0;
1170
1171         DBG_INFO("actime: %s",
1172                  time_to_asc(convert_timespec_to_time_t(ft->atime)));
1173         DBG_INFO("modtime: %s",
1174                  time_to_asc(convert_timespec_to_time_t(ft->mtime)));
1175         DBG_INFO("ctime: %s",
1176                  time_to_asc(convert_timespec_to_time_t(ft->ctime)));
1177         DBG_INFO("createtime: %s",
1178                  time_to_asc(convert_timespec_to_time_t(ft->create_time)));
1179
1180         /* Don't update the time on read-only shares */
1181         /* We need this as set_filetime (which can be called on
1182            close and other paths) can end up calling this function
1183            without the NEED_WRITE protection. Found by :
1184            Leo Weppelman <leo@wau.mis.ah.nl>
1185         */
1186
1187         if (!CAN_WRITE(conn)) {
1188                 return 0;
1189         }
1190
1191         if (SMB_VFS_FNTIMES(fsp, ft) == 0) {
1192                 ret = 0;
1193                 goto done;
1194         }
1195
1196         if((errno != EPERM) && (errno != EACCES)) {
1197                 return -1;
1198         }
1199
1200         if(!lp_dos_filetimes(SNUM(conn))) {
1201                 return -1;
1202         }
1203
1204         /* We have permission (given by the Samba admin) to
1205            break POSIX semantics and allow a user to change
1206            the time on a file they don't own but can write to
1207            (as DOS does).
1208          */
1209
1210         /* Check if we have write access. */
1211         if (can_write_to_fsp(fsp)) {
1212                 /* We are allowed to become root and change the filetime. */
1213                 become_root();
1214                 ret = SMB_VFS_FNTIMES(fsp, ft);
1215                 unbecome_root();
1216         }
1217
1218 done:
1219         if (ret == 0) {
1220                 copy_stat_ex_timestamps(fsp, ft);
1221         }
1222
1223         return ret;
1224 }
1225
1226 /******************************************************************
1227  Force a "sticky" write time on a pathname. This will always be
1228  returned on all future write time queries and set on close.
1229 ******************************************************************/
1230
1231 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1232 {
1233         if (is_omit_timespec(&mtime)) {
1234                 return true;
1235         }
1236
1237         if (!set_sticky_write_time(fileid, mtime)) {
1238                 return false;
1239         }
1240
1241         return true;
1242 }
1243
1244 /******************************************************************
1245  Force a "sticky" write time on an fsp. This will always be
1246  returned on all future write time queries and set on close.
1247 ******************************************************************/
1248
1249 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1250 {
1251         if (is_omit_timespec(&mtime)) {
1252                 return true;
1253         }
1254
1255         fsp->fsp_flags.write_time_forced = true;
1256         TALLOC_FREE(fsp->update_write_time_event);
1257
1258         return set_sticky_write_time_path(fsp->file_id, mtime);
1259 }
1260
1261 /******************************************************************
1262  Set a create time EA.
1263 ******************************************************************/
1264
1265 NTSTATUS set_create_timespec_ea(struct files_struct *fsp,
1266                                 struct timespec create_time)
1267 {
1268         uint32_t dosmode;
1269         int ret;
1270
1271         if (!lp_store_dos_attributes(SNUM(fsp->conn))) {
1272                 return NT_STATUS_OK;
1273         }
1274
1275         dosmode = fdos_mode(fsp);
1276
1277         fsp->fsp_name->st.st_ex_btime = create_time;
1278         ret = file_set_dosmode(fsp->conn, fsp->fsp_name, dosmode, NULL, false);
1279         if (ret == -1) {
1280                 return map_nt_error_from_unix(errno);
1281         }
1282
1283         DBG_DEBUG("wrote create time EA for file %s\n",
1284                 smb_fname_str_dbg(fsp->fsp_name));
1285
1286         return NT_STATUS_OK;
1287 }
1288
1289 /******************************************************************
1290  Return a create time.
1291 ******************************************************************/
1292
1293 struct timespec get_create_timespec(connection_struct *conn,
1294                                 struct files_struct *fsp,
1295                                 const struct smb_filename *smb_fname)
1296 {
1297         if (fsp != NULL) {
1298                 struct files_struct *meta_fsp = metadata_fsp(fsp);
1299                 return meta_fsp->fsp_name->st.st_ex_btime;
1300         }
1301         return smb_fname->st.st_ex_btime;
1302 }
1303
1304 /******************************************************************
1305  Return a change time (may look at EA in future).
1306 ******************************************************************/
1307
1308 struct timespec get_change_timespec(connection_struct *conn,
1309                                 struct files_struct *fsp,
1310                                 const struct smb_filename *smb_fname)
1311 {
1312         return smb_fname->st.st_ex_mtime;
1313 }