auth/credentials: don't ignore "client use kerberos" and --use-kerberos for machine...
[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         /*
359          * _SPARSE and _REPARSE_POINT are valid on get but not on
360          * set. Both are created via special fcntls.
361          */
362
363         dosattr &= (SAMBA_ATTRIBUTES_MASK|
364                     FILE_ATTRIBUTE_SPARSE|
365                     FILE_ATTRIBUTE_REPARSE_POINT);
366
367         *pattr |= dosattr;
368
369         dos_mode_debug_print(__func__, *pattr);
370
371         return NT_STATUS_OK;
372 }
373
374 NTSTATUS fget_ea_dos_attribute(struct files_struct *fsp,
375                               uint32_t *pattr)
376 {
377         DATA_BLOB blob;
378         ssize_t sizeret;
379         fstring attrstr;
380         NTSTATUS status;
381
382         if (!lp_store_dos_attributes(SNUM(fsp->conn))) {
383                 return NT_STATUS_NOT_IMPLEMENTED;
384         }
385
386         /* Don't reset pattr to zero as we may already have filename-based attributes we
387            need to preserve. */
388
389         sizeret = SMB_VFS_FGETXATTR(fsp,
390                                     SAMBA_XATTR_DOS_ATTRIB,
391                                     attrstr,
392                                     sizeof(attrstr));
393         if (sizeret == -1 && ( errno == EPERM || errno == EACCES )) {
394                 /* we may also retrieve dos attribs for unreadable files, this
395                    is why we'll retry as root. We don't use root in the first
396                    run because in cases like NFS, root might have even less
397                    rights than the real user
398                 */
399                 become_root();
400                 sizeret = SMB_VFS_FGETXATTR(fsp,
401                                             SAMBA_XATTR_DOS_ATTRIB,
402                                             attrstr,
403                                             sizeof(attrstr));
404                 unbecome_root();
405         }
406         if (sizeret == -1) {
407                 DBG_INFO("Cannot get attribute "
408                          "from EA on file %s: Error = %s\n",
409                          fsp_str_dbg(fsp), strerror(errno));
410                 return map_nt_error_from_unix(errno);
411         }
412
413         blob.data = (uint8_t *)attrstr;
414         blob.length = sizeret;
415
416         status = parse_dos_attribute_blob(fsp->fsp_name, blob, pattr);
417         if (!NT_STATUS_IS_OK(status)) {
418                 return status;
419         }
420
421         return NT_STATUS_OK;
422 }
423
424 /****************************************************************************
425  Set DOS attributes in an EA.
426  Also sets the create time.
427 ****************************************************************************/
428
429 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
430                               struct smb_filename *smb_fname,
431                               uint32_t dosmode)
432 {
433         struct xattr_DOSATTRIB dosattrib = { .version = 0, };
434         enum ndr_err_code ndr_err;
435         DATA_BLOB blob = { .data = NULL, };
436         struct timespec btime;
437         int ret;
438
439         if (!lp_store_dos_attributes(SNUM(conn))) {
440                 return NT_STATUS_NOT_IMPLEMENTED;
441         }
442
443         if (smb_fname->fsp == NULL) {
444                 /* symlink */
445                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
446         }
447         /*
448          * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in
449          * vfs_default via DMAPI if that is enabled.
450          */
451         dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
452
453         dosattrib.version = 5;
454         dosattrib.info.info5.valid_flags = XATTR_DOSINFO_ATTRIB |
455                                         XATTR_DOSINFO_CREATE_TIME;
456         dosattrib.info.info5.attrib = dosmode;
457         dosattrib.info.info5.create_time = full_timespec_to_nt_time(
458                 &smb_fname->st.st_ex_btime);
459
460         DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
461                 (unsigned int)dosmode,
462                 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
463                 smb_fname_str_dbg(smb_fname) ));
464
465         ndr_err = ndr_push_struct_blob(
466                         &blob, talloc_tos(), &dosattrib,
467                         (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
468
469         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
470                 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
471                         ndr_errstr(ndr_err)));
472                 return ndr_map_error2ntstatus(ndr_err);
473         }
474
475         if (blob.data == NULL || blob.length == 0) {
476                 /* Should this be INTERNAL_ERROR? */
477                 return NT_STATUS_INVALID_PARAMETER;
478         }
479
480         ret = SMB_VFS_FSETXATTR(smb_fname->fsp,
481                                SAMBA_XATTR_DOS_ATTRIB,
482                                blob.data, blob.length, 0);
483         if (ret != 0) {
484                 NTSTATUS status = NT_STATUS_OK;
485                 bool set_dosmode_ok = false;
486
487                 if ((errno != EPERM) && (errno != EACCES)) {
488                         DBG_INFO("Cannot set "
489                                  "attribute EA on file %s: Error = %s\n",
490                                  smb_fname_str_dbg(smb_fname), strerror(errno));
491                         return map_nt_error_from_unix(errno);
492                 }
493
494                 /* We want DOS semantics, ie allow non owner with write permission to change the
495                         bits on a file. Just like file_ntimes below.
496                 */
497
498                 /* Check if we have write access. */
499                 if (!CAN_WRITE(conn)) {
500                         return NT_STATUS_ACCESS_DENIED;
501                 }
502
503                 status = smbd_check_access_rights_fsp(conn->cwd_fsp,
504                                         smb_fname->fsp,
505                                         false,
506                                         FILE_WRITE_ATTRIBUTES);
507                 if (NT_STATUS_IS_OK(status)) {
508                         set_dosmode_ok = true;
509                 }
510
511                 if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
512                         set_dosmode_ok = can_write_to_fsp(smb_fname->fsp);
513                 }
514
515                 if (!set_dosmode_ok) {
516                         return NT_STATUS_ACCESS_DENIED;
517                 }
518
519                 become_root();
520                 ret = SMB_VFS_FSETXATTR(smb_fname->fsp,
521                                         SAMBA_XATTR_DOS_ATTRIB,
522                                         blob.data, blob.length, 0);
523                 if (ret == 0) {
524                         status = NT_STATUS_OK;
525                 }
526                 unbecome_root();
527                 if (!NT_STATUS_IS_OK(status)) {
528                         return status;
529                 }
530         }
531
532         /*
533          * We correctly stored the create time.
534          * We *always* set XATTR_DOSINFO_CREATE_TIME,
535          * so now it can no longer be considered
536          * calculated. Make sure to use the value rounded
537          * to NTTIME granularity we've stored in the xattr.
538          */
539         btime = nt_time_to_full_timespec(dosattrib.info.info5.create_time);
540         update_stat_ex_create_time(&smb_fname->st, btime);
541
542         DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
543                 (unsigned int)dosmode,
544                 smb_fname_str_dbg(smb_fname)));
545         return NT_STATUS_OK;
546 }
547
548 static uint32_t
549 dos_mode_from_name(connection_struct *conn, const char *name, uint32_t dosmode)
550 {
551         const char *p = NULL;
552         uint32_t result = dosmode;
553
554         if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
555             lp_hide_dot_files(SNUM(conn)))
556         {
557                 p = strrchr_m(name, '/');
558                 if (p) {
559                         p++;
560                 } else {
561                         p = name;
562                 }
563
564                 /* Only . and .. are not hidden. */
565                 if ((p[0] == '.') && !(ISDOT(p) || ISDOTDOT(p))) {
566                         result |= FILE_ATTRIBUTE_HIDDEN;
567                 }
568         }
569
570         if (!(result & FILE_ATTRIBUTE_HIDDEN) && IS_HIDDEN_PATH(conn, name)) {
571                 result |= FILE_ATTRIBUTE_HIDDEN;
572         }
573
574         return result;
575 }
576
577 /****************************************************************************
578  Change a unix mode to a dos mode for an ms dfs link.
579 ****************************************************************************/
580
581 uint32_t dos_mode_msdfs(connection_struct *conn,
582                         const char *name,
583                         const struct stat_ex *st)
584 {
585         uint32_t result = 0;
586
587         DEBUG(8, ("dos_mode_msdfs: %s\n", name));
588
589         if (!VALID_STAT(*st)) {
590                 return 0;
591         }
592
593         result = dos_mode_from_name(conn, name, result);
594         result |= dos_mode_from_sbuf(conn, st, NULL);
595
596         if (result == 0) {
597                 result = FILE_ATTRIBUTE_NORMAL;
598         }
599
600         result = filter_mode_by_protocol(conn_protocol(conn->sconn), result);
601
602         /*
603          * Add in that it is a reparse point
604          */
605         result |= FILE_ATTRIBUTE_REPARSE_POINT;
606
607         dos_mode_debug_print(__func__, result);
608
609         return(result);
610 }
611
612 /*
613  * check whether a file or directory is flagged as compressed.
614  */
615 static NTSTATUS dos_mode_check_compressed(struct files_struct *fsp,
616                                           bool *is_compressed)
617 {
618         NTSTATUS status;
619         uint16_t compression_fmt;
620
621         status = SMB_VFS_FGET_COMPRESSION(
622                 fsp->conn, talloc_tos(), fsp, &compression_fmt);
623         if (!NT_STATUS_IS_OK(status)) {
624                 return status;
625         }
626
627         if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
628                 *is_compressed = true;
629         } else {
630                 *is_compressed = false;
631         }
632         return NT_STATUS_OK;
633 }
634
635 static uint32_t dos_mode_post(uint32_t dosmode,
636                               struct files_struct *fsp,
637                               const char *func)
638 {
639         struct smb_filename *smb_fname = NULL;
640         NTSTATUS status;
641
642         if (fsp != NULL) {
643                 smb_fname = fsp->fsp_name;
644         }
645         SMB_ASSERT(smb_fname != NULL);
646
647         /*
648          * According to MS-FSA a stream name does not have
649          * separate DOS attribute metadata, so we must return
650          * the DOS attribute from the base filename. With one caveat,
651          * a non-default stream name can never be a directory.
652          *
653          * As this is common to all streams data stores, we handle
654          * it here instead of inside all stream VFS modules.
655          *
656          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
657          */
658
659         if (is_named_stream(smb_fname)) {
660                 /* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
661                 dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
662         }
663
664         if (fsp->conn->fs_capabilities & FILE_FILE_COMPRESSION) {
665                 bool compressed = false;
666
667                 status = dos_mode_check_compressed(fsp, &compressed);
668                 if (NT_STATUS_IS_OK(status) && compressed) {
669                         dosmode |= FILE_ATTRIBUTE_COMPRESSED;
670                 }
671         }
672
673         dosmode |= dos_mode_from_name(fsp->conn, smb_fname->base_name, dosmode);
674
675         if (S_ISDIR(smb_fname->st.st_ex_mode)) {
676                 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
677         } else if (dosmode == 0) {
678                 dosmode = FILE_ATTRIBUTE_NORMAL;
679         }
680
681         dosmode = filter_mode_by_protocol(conn_protocol(fsp->conn->sconn),
682                                           dosmode);
683
684         dos_mode_debug_print(func, dosmode);
685         return dosmode;
686 }
687
688 /****************************************************************************
689  Change a unix mode to a dos mode.
690  May also read the create timespec into the stat struct in smb_fname
691  if "store dos attributes" is true.
692 ****************************************************************************/
693
694 uint32_t fdos_mode(struct files_struct *fsp)
695 {
696         uint32_t result = 0;
697         NTSTATUS status = NT_STATUS_OK;
698
699         DBG_DEBUG("%s\n", fsp_str_dbg(fsp));
700
701         if (fsp->fake_file_handle != NULL) {
702                 return dosmode_from_fake_filehandle(fsp->fake_file_handle);
703         }
704
705         if (!VALID_STAT(fsp->fsp_name->st)) {
706                 return 0;
707         }
708
709         if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
710                 return FILE_ATTRIBUTE_NORMAL;
711         }
712
713         if (fsp->fsp_name->st.cached_dos_attributes != FILE_ATTRIBUTE_INVALID) {
714                 return fsp->fsp_name->st.cached_dos_attributes;
715         }
716
717         /* Get the DOS attributes via the VFS if we can */
718         status = SMB_VFS_FGET_DOS_ATTRIBUTES(fsp->conn,
719                                              metadata_fsp(fsp),
720                                              &result);
721         if (!NT_STATUS_IS_OK(status)) {
722                 /*
723                  * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
724                  */
725                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
726                         result |= dos_mode_from_sbuf(fsp->conn,
727                                                      &fsp->fsp_name->st,
728                                                      fsp);
729                 }
730         }
731
732         fsp->fsp_name->st.cached_dos_attributes = dos_mode_post(result, fsp, __func__);
733         return fsp->fsp_name->st.cached_dos_attributes;
734 }
735
736 struct dos_mode_at_state {
737         files_struct *dir_fsp;
738         struct smb_filename *smb_fname;
739         uint32_t dosmode;
740 };
741
742 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq);
743
744 struct tevent_req *dos_mode_at_send(TALLOC_CTX *mem_ctx,
745                                     struct tevent_context *ev,
746                                     files_struct *dir_fsp,
747                                     struct smb_filename *smb_fname)
748 {
749         struct tevent_req *req = NULL;
750         struct dos_mode_at_state *state = NULL;
751         struct tevent_req *subreq = NULL;
752
753         DBG_DEBUG("%s\n", smb_fname_str_dbg(smb_fname));
754
755         req = tevent_req_create(mem_ctx, &state,
756                                 struct dos_mode_at_state);
757         if (req == NULL) {
758                 return NULL;
759         }
760
761         *state = (struct dos_mode_at_state) {
762                 .dir_fsp = dir_fsp,
763                 .smb_fname = smb_fname,
764         };
765
766         if (!VALID_STAT(smb_fname->st)) {
767                 tevent_req_done(req);
768                 return tevent_req_post(req, ev);
769         }
770
771         if (smb_fname->fsp == NULL) {
772                 if (ISDOTDOT(smb_fname->base_name)) {
773                         /*
774                          * smb_fname->fsp is explicitly closed
775                          * for ".." to prevent meta-data leakage.
776                          */
777                         state->dosmode = FILE_ATTRIBUTE_DIRECTORY;
778                 } else {
779                         /*
780                          * This is a symlink in POSIX context.
781                          * FIXME ? Should we move to returning
782                          * FILE_ATTRIBUTE_REPARSE_POINT here ?
783                          */
784                         state->dosmode = FILE_ATTRIBUTE_NORMAL;
785                 }
786                 tevent_req_done(req);
787                 return tevent_req_post(req, ev);
788         }
789
790         subreq = SMB_VFS_GET_DOS_ATTRIBUTES_SEND(state,
791                                                  ev,
792                                                  dir_fsp,
793                                                  smb_fname);
794         if (tevent_req_nomem(subreq, req)) {
795                 return tevent_req_post(req, ev);
796         }
797         tevent_req_set_callback(subreq, dos_mode_at_vfs_get_dosmode_done, req);
798
799         return req;
800 }
801
802 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
803 {
804         struct tevent_req *req =
805                 tevent_req_callback_data(subreq,
806                 struct tevent_req);
807         struct dos_mode_at_state *state =
808                 tevent_req_data(req,
809                 struct dos_mode_at_state);
810         struct vfs_aio_state aio_state;
811         NTSTATUS status;
812         bool ok;
813
814         /*
815          * Make sure we run as the user again
816          */
817         ok = change_to_user_and_service_by_fsp(state->dir_fsp);
818         SMB_ASSERT(ok);
819
820         status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV(subreq,
821                                                  &aio_state,
822                                                  &state->dosmode);
823         TALLOC_FREE(subreq);
824         if (!NT_STATUS_IS_OK(status)) {
825                 /*
826                  * Both the sync dos_mode() as well as the async
827                  * dos_mode_at_[send|recv] have no real error return, the only
828                  * unhandled error is when the stat info in smb_fname is not
829                  * valid (cf the checks in dos_mode() and dos_mode_at_send().
830                  *
831                  * If SMB_VFS_GET_DOS_ATTRIBUTES[_SEND|_RECV] fails we must call
832                  * dos_mode_post() which also does the mapping of a last resort
833                  * from S_IFMT(st_mode).
834                  *
835                  * Only if we get NT_STATUS_NOT_IMPLEMENTED or
836                  * NT_STATUS_NOT_SUPPORTED from a stacked VFS module we must
837                  * fallback to sync processing.
838                  */
839                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) &&
840                     !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED))
841                 {
842                         /*
843                          * state->dosmode should still be 0, but reset
844                          * it to be sure.
845                          */
846                         state->dosmode = 0;
847                         status = NT_STATUS_OK;
848                 }
849         }
850         if (NT_STATUS_IS_OK(status)) {
851                 state->dosmode = dos_mode_post(state->dosmode,
852                                                state->smb_fname->fsp,
853                                                __func__);
854                 tevent_req_done(req);
855                 return;
856         }
857
858         /*
859          * Fall back to sync dos_mode() if we got NOT_IMPLEMENTED.
860          */
861
862         state->dosmode = fdos_mode(state->smb_fname->fsp);
863         tevent_req_done(req);
864         return;
865 }
866
867 NTSTATUS dos_mode_at_recv(struct tevent_req *req, uint32_t *dosmode)
868 {
869         struct dos_mode_at_state *state =
870                 tevent_req_data(req,
871                 struct dos_mode_at_state);
872         NTSTATUS status;
873
874         if (tevent_req_is_nterror(req, &status)) {
875                 tevent_req_received(req);
876                 return status;
877         }
878
879         *dosmode = state->dosmode;
880         tevent_req_received(req);
881         return NT_STATUS_OK;
882 }
883
884 /*******************************************************************
885  chmod a file - but preserve some bits.
886  If "store dos attributes" is also set it will store the create time
887  from the stat struct in smb_fname (in NTTIME format) in the EA
888  attribute also.
889 ********************************************************************/
890
891 int file_set_dosmode(connection_struct *conn,
892                      struct smb_filename *smb_fname,
893                      uint32_t dosmode,
894                      struct smb_filename *parent_dir,
895                      bool newfile)
896 {
897         int mask=0;
898         mode_t tmp;
899         mode_t unixmode;
900         int ret = -1;
901         NTSTATUS status;
902
903         if (!CAN_WRITE(conn)) {
904                 errno = EROFS;
905                 return -1;
906         }
907
908         if (S_ISLNK(smb_fname->st.st_ex_mode)) {
909                 /* A symlink in POSIX context, ignore */
910                 return 0;
911         }
912
913         if ((S_ISDIR(smb_fname->st.st_ex_mode)) &&
914             (dosmode & FILE_ATTRIBUTE_TEMPORARY))
915         {
916                 errno = EINVAL;
917                 return -1;
918         }
919
920         dosmode &= SAMBA_ATTRIBUTES_MASK;
921
922         DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
923                   dosmode, smb_fname_str_dbg(smb_fname)));
924
925         if (smb_fname->fsp == NULL) {
926                 errno = ENOENT;
927                 return -1;
928         }
929
930         if ((smb_fname->fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
931             !lp_store_dos_attributes(SNUM(conn)))
932         {
933                 return 0;
934         }
935
936         unixmode = smb_fname->st.st_ex_mode;
937
938         get_acl_group_bits(conn, smb_fname->fsp, &smb_fname->st.st_ex_mode);
939
940         if (S_ISDIR(smb_fname->st.st_ex_mode))
941                 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
942         else
943                 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
944
945         /* Store the DOS attributes in an EA by preference. */
946         status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn,
947                                              metadata_fsp(smb_fname->fsp),
948                                              dosmode);
949         if (NT_STATUS_IS_OK(status)) {
950                 smb_fname->st.cached_dos_attributes = dosmode;
951                 ret = 0;
952                 goto done;
953         }
954
955         /*
956          * Only fall back to using UNIX modes if
957          * we get NOT_IMPLEMENTED.
958          */
959         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
960                 errno = map_errno_from_nt_status(status);
961                 return -1;
962         }
963
964         /* Fall back to UNIX modes. */
965         unixmode = unix_mode(
966                 conn,
967                 dosmode,
968                 smb_fname,
969                 parent_dir != NULL ? parent_dir->fsp : NULL);
970
971         /* preserve the file type bits */
972         mask |= S_IFMT;
973
974         /* preserve the s bits */
975         mask |= (S_ISUID | S_ISGID);
976
977         /* preserve the t bit */
978 #ifdef S_ISVTX
979         mask |= S_ISVTX;
980 #endif
981
982         /* possibly preserve the x bits */
983         if (!MAP_ARCHIVE(conn))
984                 mask |= S_IXUSR;
985         if (!MAP_SYSTEM(conn))
986                 mask |= S_IXGRP;
987         if (!MAP_HIDDEN(conn))
988                 mask |= S_IXOTH;
989
990         unixmode |= (smb_fname->st.st_ex_mode & mask);
991
992         /* if we previously had any r bits set then leave them alone */
993         if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
994                 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
995                 unixmode |= tmp;
996         }
997
998         /* if we previously had any w bits set then leave them alone
999                 whilst adding in the new w bits, if the new mode is not rdonly */
1000         if (!(dosmode & FILE_ATTRIBUTE_READONLY)) {
1001                 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
1002         }
1003
1004         /*
1005          * From the chmod 2 man page:
1006          *
1007          * "If the calling process is not privileged, and the group of the file
1008          * does not match the effective group ID of the process or one of its
1009          * supplementary group IDs, the S_ISGID bit will be turned off, but
1010          * this will not cause an error to be returned."
1011          *
1012          * Simply refuse to do the chmod in this case.
1013          */
1014
1015         if (S_ISDIR(smb_fname->st.st_ex_mode) &&
1016             (unixmode & S_ISGID) &&
1017             geteuid() != sec_initial_uid() &&
1018             !current_user_in_group(conn, smb_fname->st.st_ex_gid))
1019         {
1020                 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
1021                         "set for directory %s\n",
1022                         smb_fname_str_dbg(smb_fname)));
1023                 errno = EPERM;
1024                 return -1;
1025         }
1026
1027         ret = SMB_VFS_FCHMOD(smb_fname->fsp, unixmode);
1028         if (ret == 0) {
1029                 goto done;
1030         }
1031
1032         if((errno != EPERM) && (errno != EACCES))
1033                 return -1;
1034
1035         if(!lp_dos_filemode(SNUM(conn)))
1036                 return -1;
1037
1038         /* We want DOS semantics, ie allow non owner with write permission to change the
1039                 bits on a file. Just like file_ntimes below.
1040         */
1041
1042         if (!can_write_to_fsp(smb_fname->fsp))
1043         {
1044                 errno = EACCES;
1045                 return -1;
1046         }
1047
1048         become_root();
1049         ret = SMB_VFS_FCHMOD(smb_fname->fsp, unixmode);
1050         unbecome_root();
1051
1052 done:
1053         if (!newfile) {
1054                 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1055                              FILE_NOTIFY_CHANGE_ATTRIBUTES,
1056                              smb_fname->base_name);
1057         }
1058         if (ret == 0) {
1059                 smb_fname->st.st_ex_mode = unixmode;
1060         }
1061
1062         return( ret );
1063 }
1064
1065
1066 NTSTATUS file_set_sparse(connection_struct *conn,
1067                          files_struct *fsp,
1068                          bool sparse)
1069 {
1070         const struct loadparm_substitution *lp_sub =
1071                 loadparm_s3_global_substitution();
1072         uint32_t old_dosmode;
1073         uint32_t new_dosmode;
1074         NTSTATUS status;
1075
1076         if (!CAN_WRITE(conn)) {
1077                 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1078                         "on readonly share[%s]\n",
1079                         smb_fname_str_dbg(fsp->fsp_name),
1080                         sparse,
1081                         lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1082                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1083         }
1084
1085         /*
1086          * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
1087          * following access flags are granted.
1088          */
1089         status = check_any_access_fsp(fsp,
1090                                   FILE_WRITE_DATA
1091                                   | FILE_WRITE_ATTRIBUTES
1092                                   | SEC_FILE_APPEND_DATA);
1093         if (!NT_STATUS_IS_OK(status)) {
1094                 DBG_DEBUG("fname[%s] set[%u] "
1095                           "access_mask[0x%08X] - access denied\n",
1096                           smb_fname_str_dbg(fsp->fsp_name),
1097                           sparse,
1098                           fsp->access_mask);
1099                 return status;
1100         }
1101
1102         if (fsp->fsp_flags.is_directory) {
1103                 DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
1104                           (sparse ? "set" : "clear"),
1105                           smb_fname_str_dbg(fsp->fsp_name)));
1106                 return NT_STATUS_INVALID_PARAMETER;
1107         }
1108
1109         if (IS_IPC(conn) || IS_PRINT(conn)) {
1110                 DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
1111                           (sparse ? "set" : "clear")));
1112                 return NT_STATUS_INVALID_PARAMETER;
1113         }
1114
1115         if (fsp_is_alternate_stream(fsp)) {
1116                 /*
1117                  * MS-FSA 2.1.1.5 IsSparse
1118                  *
1119                  * This is a per stream attribute, but our backends don't
1120                  * support it a consistent way, therefore just pretend
1121                  * success and ignore the request.
1122                  */
1123                 DBG_DEBUG("Ignoring request to set FILE_ATTRIBUTE_SPARSE on "
1124                           "[%s]\n", fsp_str_dbg(fsp));
1125                 return NT_STATUS_OK;
1126         }
1127
1128         DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
1129                   sparse, smb_fname_str_dbg(fsp->fsp_name)));
1130
1131         if (!lp_store_dos_attributes(SNUM(conn))) {
1132                 return NT_STATUS_INVALID_DEVICE_REQUEST;
1133         }
1134
1135         status = vfs_stat_fsp(fsp);
1136         if (!NT_STATUS_IS_OK(status)) {
1137                 return status;
1138         }
1139
1140         old_dosmode = fdos_mode(fsp);
1141
1142         if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1143                 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
1144         } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1145                 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
1146         } else {
1147                 return NT_STATUS_OK;
1148         }
1149
1150         /* Store the DOS attributes in an EA. */
1151         status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
1152         if (!NT_STATUS_IS_OK(status)) {
1153                 return status;
1154         }
1155
1156         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1157                      FILE_NOTIFY_CHANGE_ATTRIBUTES,
1158                      fsp->fsp_name->base_name);
1159
1160         fsp->fsp_name->st.cached_dos_attributes = new_dosmode;
1161         fsp->fsp_flags.is_sparse = sparse;
1162
1163         return NT_STATUS_OK;
1164 }
1165
1166 /*******************************************************************
1167  Wrapper around the VFS ntimes that possibly allows DOS semantics rather
1168  than POSIX.
1169 *******************************************************************/
1170
1171 int file_ntimes(connection_struct *conn,
1172                 files_struct *fsp,
1173                 struct smb_file_time *ft)
1174 {
1175         int ret = -1;
1176
1177         errno = 0;
1178
1179         DBG_INFO("actime: %s",
1180                  time_to_asc(convert_timespec_to_time_t(ft->atime)));
1181         DBG_INFO("modtime: %s",
1182                  time_to_asc(convert_timespec_to_time_t(ft->mtime)));
1183         DBG_INFO("ctime: %s",
1184                  time_to_asc(convert_timespec_to_time_t(ft->ctime)));
1185         DBG_INFO("createtime: %s",
1186                  time_to_asc(convert_timespec_to_time_t(ft->create_time)));
1187
1188         /* Don't update the time on read-only shares */
1189         /* We need this as set_filetime (which can be called on
1190            close and other paths) can end up calling this function
1191            without the NEED_WRITE protection. Found by :
1192            Leo Weppelman <leo@wau.mis.ah.nl>
1193         */
1194
1195         if (!CAN_WRITE(conn)) {
1196                 return 0;
1197         }
1198
1199         if (SMB_VFS_FNTIMES(fsp, ft) == 0) {
1200                 ret = 0;
1201                 goto done;
1202         }
1203
1204         if((errno != EPERM) && (errno != EACCES)) {
1205                 return -1;
1206         }
1207
1208         if(!lp_dos_filetimes(SNUM(conn))) {
1209                 return -1;
1210         }
1211
1212         /* We have permission (given by the Samba admin) to
1213            break POSIX semantics and allow a user to change
1214            the time on a file they don't own but can write to
1215            (as DOS does).
1216          */
1217
1218         /* Check if we have write access. */
1219         if (can_write_to_fsp(fsp)) {
1220                 /* We are allowed to become root and change the filetime. */
1221                 become_root();
1222                 ret = SMB_VFS_FNTIMES(fsp, ft);
1223                 unbecome_root();
1224         }
1225
1226 done:
1227         if (ret == 0) {
1228                 copy_stat_ex_timestamps(fsp, ft);
1229         }
1230
1231         return ret;
1232 }
1233
1234 /******************************************************************
1235  Force a "sticky" write time on a pathname. This will always be
1236  returned on all future write time queries and set on close.
1237 ******************************************************************/
1238
1239 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1240 {
1241         if (is_omit_timespec(&mtime)) {
1242                 return true;
1243         }
1244
1245         if (!set_sticky_write_time(fileid, mtime)) {
1246                 return false;
1247         }
1248
1249         return true;
1250 }
1251
1252 /******************************************************************
1253  Force a "sticky" write time on an fsp. This will always be
1254  returned on all future write time queries and set on close.
1255 ******************************************************************/
1256
1257 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1258 {
1259         if (is_omit_timespec(&mtime)) {
1260                 return true;
1261         }
1262
1263         fsp->fsp_flags.write_time_forced = true;
1264         TALLOC_FREE(fsp->update_write_time_event);
1265
1266         return set_sticky_write_time_path(fsp->file_id, mtime);
1267 }
1268
1269 /******************************************************************
1270  Set a create time EA.
1271 ******************************************************************/
1272
1273 NTSTATUS set_create_timespec_ea(struct files_struct *fsp,
1274                                 struct timespec create_time)
1275 {
1276         uint32_t dosmode;
1277         int ret;
1278
1279         if (!lp_store_dos_attributes(SNUM(fsp->conn))) {
1280                 return NT_STATUS_OK;
1281         }
1282
1283         dosmode = fdos_mode(fsp);
1284
1285         fsp->fsp_name->st.st_ex_btime = create_time;
1286         ret = file_set_dosmode(fsp->conn, fsp->fsp_name, dosmode, NULL, false);
1287         if (ret == -1) {
1288                 return map_nt_error_from_unix(errno);
1289         }
1290
1291         DBG_DEBUG("wrote create time EA for file %s\n",
1292                 smb_fname_str_dbg(fsp->fsp_name));
1293
1294         return NT_STATUS_OK;
1295 }
1296
1297 /******************************************************************
1298  Return a create time.
1299 ******************************************************************/
1300
1301 struct timespec get_create_timespec(connection_struct *conn,
1302                                 struct files_struct *fsp,
1303                                 const struct smb_filename *smb_fname)
1304 {
1305         if (fsp != NULL) {
1306                 struct files_struct *meta_fsp = metadata_fsp(fsp);
1307                 return meta_fsp->fsp_name->st.st_ex_btime;
1308         }
1309         return smb_fname->st.st_ex_btime;
1310 }
1311
1312 /******************************************************************
1313  Return a change time (may look at EA in future).
1314 ******************************************************************/
1315
1316 struct timespec get_change_timespec(connection_struct *conn,
1317                                 struct files_struct *fsp,
1318                                 const struct smb_filename *smb_fname)
1319 {
1320         return smb_fname->st.st_ex_mtime;
1321 }