2 Unix SMB/CIFS implementation.
3 dos mode handling functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) James Peach 2006
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.
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.
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/>.
23 extern enum protocol_types Protocol
;
25 static uint32_t filter_mode_by_protocol(uint32_t mode
)
27 if (Protocol
<= PROTOCOL_LANMAN2
) {
28 DEBUG(10,("filter_mode_by_protocol: "
29 "filtering result 0x%x to 0x%x\n",
31 (unsigned int)(mode
& 0x3f) ));
37 static int set_sparse_flag(const SMB_STRUCT_STAT
* const sbuf
)
39 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
40 if (sbuf
->st_size
> sbuf
->st_blocks
* (SMB_OFF_T
)STAT_ST_BLOCKSIZE
) {
41 return FILE_ATTRIBUTE_SPARSE
;
47 /****************************************************************************
48 Change a dos mode to a unix mode.
49 Base permission for files:
50 if creating file and inheriting (i.e. parent_dir != NULL)
51 apply read/write bits from parent directory.
53 everybody gets read bit set
54 dos readonly is represented in unix by removing everyone's write bit
55 dos archive is represented in unix by the user's execute bit
56 dos system is represented in unix by the group's execute bit
57 dos hidden is represented in unix by the other's execute bit
59 Then apply create mask,
62 Base permission for directories:
63 dos directory is represented in unix by unix's dir bit and the exec bit
65 Then apply create mask,
68 ****************************************************************************/
70 mode_t
unix_mode(connection_struct
*conn
, int dosmode
, const char *fname
,
71 const char *inherit_from_dir
)
73 mode_t result
= (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
74 mode_t dir_mode
= 0; /* Mode of the inherit_from directory if
77 if (!lp_store_dos_attributes(SNUM(conn
)) && IS_DOS_READONLY(dosmode
)) {
78 result
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
81 if (fname
&& (inherit_from_dir
!= NULL
)
82 && lp_inherit_perms(SNUM(conn
))) {
85 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname
,
87 if (SMB_VFS_STAT(conn
, inherit_from_dir
, &sbuf
) != 0) {
88 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname
,
89 inherit_from_dir
, strerror(errno
)));
90 return(0); /* *** shouldn't happen! *** */
93 /* Save for later - but explicitly remove setuid bit for safety. */
94 dir_mode
= sbuf
.st_mode
& ~S_ISUID
;
95 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname
,(int)dir_mode
));
100 if (IS_DOS_DIR(dosmode
)) {
101 /* We never make directories read only for the owner as under DOS a user
102 can always create a file in a read-only directory. */
103 result
|= (S_IFDIR
| S_IWUSR
);
106 /* Inherit mode of parent directory. */
109 /* Provisionally add all 'x' bits */
110 result
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
112 /* Apply directory mask */
113 result
&= lp_dir_mask(SNUM(conn
));
114 /* Add in force bits */
115 result
|= lp_force_dir_mode(SNUM(conn
));
118 if (lp_map_archive(SNUM(conn
)) && IS_DOS_ARCHIVE(dosmode
))
121 if (lp_map_system(SNUM(conn
)) && IS_DOS_SYSTEM(dosmode
))
124 if (lp_map_hidden(SNUM(conn
)) && IS_DOS_HIDDEN(dosmode
))
128 /* Inherit 666 component of parent directory mode */
129 result
|= dir_mode
& (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
131 /* Apply mode mask */
132 result
&= lp_create_mask(SNUM(conn
));
133 /* Add in force bits */
134 result
|= lp_force_create_mode(SNUM(conn
));
138 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname
,(int)result
));
142 /****************************************************************************
143 Change a unix mode to a dos mode.
144 ****************************************************************************/
146 static uint32
dos_mode_from_sbuf(connection_struct
*conn
, const char *path
, SMB_STRUCT_STAT
*sbuf
)
149 enum mapreadonly_options ro_opts
= (enum mapreadonly_options
)lp_map_readonly(SNUM(conn
));
151 if (ro_opts
== MAP_READONLY_YES
) {
152 /* Original Samba method - map inverse of user "w" bit. */
153 if ((sbuf
->st_mode
& S_IWUSR
) == 0) {
156 } else if (ro_opts
== MAP_READONLY_PERMISSIONS
) {
157 /* Check actual permissions for read-only. */
158 if (!can_write_to_file(conn
, path
, sbuf
)) {
161 } /* Else never set the readonly bit. */
163 if (MAP_ARCHIVE(conn
) && ((sbuf
->st_mode
& S_IXUSR
) != 0))
166 if (MAP_SYSTEM(conn
) && ((sbuf
->st_mode
& S_IXGRP
) != 0))
169 if (MAP_HIDDEN(conn
) && ((sbuf
->st_mode
& S_IXOTH
) != 0))
172 if (S_ISDIR(sbuf
->st_mode
))
173 result
= aDIR
| (result
& aRONLY
);
175 result
|= set_sparse_flag(sbuf
);
179 if (S_ISLNK(sbuf
->st_mode
) && S_ISDIR(sbuf
->st_mode
))
184 DEBUG(8,("dos_mode_from_sbuf returning "));
186 if (result
& aHIDDEN
) DEBUG(8, ("h"));
187 if (result
& aRONLY
) DEBUG(8, ("r"));
188 if (result
& aSYSTEM
) DEBUG(8, ("s"));
189 if (result
& aDIR
) DEBUG(8, ("d"));
190 if (result
& aARCH
) DEBUG(8, ("a"));
196 /****************************************************************************
197 Get DOS attributes from an EA.
198 ****************************************************************************/
200 static bool get_ea_dos_attribute(connection_struct
*conn
, const char *path
,SMB_STRUCT_STAT
*sbuf
, uint32
*pattr
)
204 unsigned int dosattr
;
206 if (!lp_store_dos_attributes(SNUM(conn
))) {
210 /* Don't reset pattr to zero as we may already have filename-based attributes we
213 sizeret
= SMB_VFS_GETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, sizeof(attrstr
));
217 || errno
== ENOTSUP
) {
221 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
222 path
, strerror(errno
) ));
223 set_store_dos_attributes(SNUM(conn
), False
);
227 /* Null terminate string. */
228 attrstr
[sizeret
] = 0;
229 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path
, attrstr
));
231 if (sizeret
< 2 || attrstr
[0] != '0' || attrstr
[1] != 'x' ||
232 sscanf(attrstr
, "%x", &dosattr
) != 1) {
233 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path
, attrstr
));
237 if (S_ISDIR(sbuf
->st_mode
)) {
240 *pattr
= (uint32
)(dosattr
& SAMBA_ATTRIBUTES_MASK
);
242 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr
));
244 if (dosattr
& aHIDDEN
) DEBUG(8, ("h"));
245 if (dosattr
& aRONLY
) DEBUG(8, ("r"));
246 if (dosattr
& aSYSTEM
) DEBUG(8, ("s"));
247 if (dosattr
& aDIR
) DEBUG(8, ("d"));
248 if (dosattr
& aARCH
) DEBUG(8, ("a"));
255 /****************************************************************************
256 Set DOS attributes in an EA.
257 ****************************************************************************/
259 static bool set_ea_dos_attribute(connection_struct
*conn
, const char *path
, SMB_STRUCT_STAT
*sbuf
, uint32 dosmode
)
262 files_struct
*fsp
= NULL
;
265 if (!lp_store_dos_attributes(SNUM(conn
))) {
269 snprintf(attrstr
, sizeof(attrstr
)-1, "0x%x", dosmode
& SAMBA_ATTRIBUTES_MASK
);
270 if (SMB_VFS_SETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, strlen(attrstr
), 0) == -1) {
271 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
274 || errno
== ENOTSUP
) {
278 DEBUG(1,("set_ea_dos_attributes: Cannot set attribute EA on file %s: Error = %s\n",
279 path
, strerror(errno
) ));
280 set_store_dos_attributes(SNUM(conn
), False
);
285 /* We want DOS semantics, ie allow non owner with write permission to change the
286 bits on a file. Just like file_ntimes below.
289 /* Check if we have write access. */
290 if(!CAN_WRITE(conn
) || !lp_dos_filemode(SNUM(conn
)))
294 * We need to open the file with write access whilst
295 * still in our current user context. This ensures we
296 * are not violating security in doing the setxattr.
299 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
,path
,sbuf
,&fsp
)))
302 if (SMB_VFS_SETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, strlen(attrstr
), 0) == 0) {
306 close_file_fchmod(fsp
);
309 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr
, path
));
313 /****************************************************************************
314 Change a unix mode to a dos mode for an ms dfs link.
315 ****************************************************************************/
317 uint32
dos_mode_msdfs(connection_struct
*conn
, const char *path
,SMB_STRUCT_STAT
*sbuf
)
321 DEBUG(8,("dos_mode_msdfs: %s\n", path
));
323 if (!VALID_STAT(*sbuf
)) {
327 /* First do any modifications that depend on the path name. */
328 /* hide files with a name starting with a . */
329 if (lp_hide_dot_files(SNUM(conn
))) {
330 const char *p
= strrchr_m(path
,'/');
337 /* Only . and .. are not hidden. */
338 if (p
[0] == '.' && !((p
[1] == '\0') ||
339 (p
[1] == '.' && p
[2] == '\0'))) {
344 result
|= dos_mode_from_sbuf(conn
, path
, sbuf
);
346 /* Optimization : Only call is_hidden_path if it's not already
348 if (!(result
& aHIDDEN
) && IS_HIDDEN_PATH(conn
,path
)) {
353 result
= FILE_ATTRIBUTE_NORMAL
;
356 result
= filter_mode_by_protocol(result
);
358 DEBUG(8,("dos_mode_msdfs returning "));
360 if (result
& aHIDDEN
) DEBUG(8, ("h"));
361 if (result
& aRONLY
) DEBUG(8, ("r"));
362 if (result
& aSYSTEM
) DEBUG(8, ("s"));
363 if (result
& aDIR
) DEBUG(8, ("d"));
364 if (result
& aARCH
) DEBUG(8, ("a"));
365 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
372 /****************************************************************************
373 Change a unix mode to a dos mode.
374 ****************************************************************************/
376 uint32
dos_mode(connection_struct
*conn
, const char *path
,SMB_STRUCT_STAT
*sbuf
)
381 DEBUG(8,("dos_mode: %s\n", path
));
383 if (!VALID_STAT(*sbuf
)) {
387 /* First do any modifications that depend on the path name. */
388 /* hide files with a name starting with a . */
389 if (lp_hide_dot_files(SNUM(conn
))) {
390 const char *p
= strrchr_m(path
,'/');
397 /* Only . and .. are not hidden. */
398 if (p
[0] == '.' && !((p
[1] == '\0') ||
399 (p
[1] == '.' && p
[2] == '\0'))) {
404 /* Get the DOS attributes from an EA by preference. */
405 if (get_ea_dos_attribute(conn
, path
, sbuf
, &result
)) {
406 result
|= set_sparse_flag(sbuf
);
408 result
|= dos_mode_from_sbuf(conn
, path
, sbuf
);
412 offline
= SMB_VFS_IS_OFFLINE(conn
, path
, sbuf
);
413 if (S_ISREG(sbuf
->st_mode
) && offline
) {
414 result
|= FILE_ATTRIBUTE_OFFLINE
;
417 /* Optimization : Only call is_hidden_path if it's not already
419 if (!(result
& aHIDDEN
) && IS_HIDDEN_PATH(conn
,path
)) {
424 result
= FILE_ATTRIBUTE_NORMAL
;
427 result
= filter_mode_by_protocol(result
);
429 DEBUG(8,("dos_mode returning "));
431 if (result
& aHIDDEN
) DEBUG(8, ("h"));
432 if (result
& aRONLY
) DEBUG(8, ("r"));
433 if (result
& aSYSTEM
) DEBUG(8, ("s"));
434 if (result
& aDIR
) DEBUG(8, ("d"));
435 if (result
& aARCH
) DEBUG(8, ("a"));
436 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
443 /*******************************************************************
444 chmod a file - but preserve some bits.
445 ********************************************************************/
447 int file_set_dosmode(connection_struct
*conn
, const char *fname
,
448 uint32 dosmode
, SMB_STRUCT_STAT
*st
,
449 const char *parent_dir
,
456 int ret
= -1, lret
= -1;
459 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
460 dosmode
&= (SAMBA_ATTRIBUTES_MASK
| FILE_ATTRIBUTE_OFFLINE
);
462 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode
, fname
));
465 SET_STAT_INVALID(st1
);
469 if (!VALID_STAT(*st
)) {
470 if (SMB_VFS_STAT(conn
,fname
,st
))
474 unixmode
= st
->st_mode
;
476 get_acl_group_bits(conn
, fname
, &st
->st_mode
);
478 if (S_ISDIR(st
->st_mode
))
483 old_mode
= dos_mode(conn
,fname
,st
);
485 if (dosmode
& FILE_ATTRIBUTE_OFFLINE
) {
486 if (!(old_mode
& FILE_ATTRIBUTE_OFFLINE
)) {
487 lret
= SMB_VFS_SET_OFFLINE(conn
, fname
);
489 DEBUG(0, ("set_dos_mode: client has asked to set "
490 "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
491 "an error while setting it or it is not supported.\n",
497 dosmode
&= ~FILE_ATTRIBUTE_OFFLINE
;
498 old_mode
&= ~FILE_ATTRIBUTE_OFFLINE
;
500 if (old_mode
== dosmode
) {
501 st
->st_mode
= unixmode
;
505 /* Store the DOS attributes in an EA by preference. */
506 if (set_ea_dos_attribute(conn
, fname
, st
, dosmode
)) {
508 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
509 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
511 st
->st_mode
= unixmode
;
515 unixmode
= unix_mode(conn
,dosmode
,fname
, parent_dir
);
517 /* preserve the s bits */
518 mask
|= (S_ISUID
| S_ISGID
);
520 /* preserve the t bit */
525 /* possibly preserve the x bits */
526 if (!MAP_ARCHIVE(conn
))
528 if (!MAP_SYSTEM(conn
))
530 if (!MAP_HIDDEN(conn
))
533 unixmode
|= (st
->st_mode
& mask
);
535 /* if we previously had any r bits set then leave them alone */
536 if ((tmp
= st
->st_mode
& (S_IRUSR
|S_IRGRP
|S_IROTH
))) {
537 unixmode
&= ~(S_IRUSR
|S_IRGRP
|S_IROTH
);
541 /* if we previously had any w bits set then leave them alone
542 whilst adding in the new w bits, if the new mode is not rdonly */
543 if (!IS_DOS_READONLY(dosmode
)) {
544 unixmode
|= (st
->st_mode
& (S_IWUSR
|S_IWGRP
|S_IWOTH
));
547 ret
= SMB_VFS_CHMOD(conn
, fname
, unixmode
);
549 if(!newfile
|| (lret
!= -1)) {
550 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
551 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
553 st
->st_mode
= unixmode
;
557 if((errno
!= EPERM
) && (errno
!= EACCES
))
560 if(!lp_dos_filemode(SNUM(conn
)))
563 /* We want DOS semantics, ie allow non owner with write permission to change the
564 bits on a file. Just like file_ntimes below.
567 /* Check if we have write access. */
568 if (CAN_WRITE(conn
)) {
570 * We need to open the file with write access whilst
571 * still in our current user context. This ensures we
572 * are not violating security in doing the fchmod.
573 * This file open does *not* break any oplocks we are
574 * holding. We need to review this.... may need to
575 * break batch oplocks open by others. JRA.
578 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
,fname
,st
,&fsp
)))
581 ret
= SMB_VFS_FCHMOD(fsp
, unixmode
);
583 close_file_fchmod(fsp
);
585 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
586 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
589 st
->st_mode
= unixmode
;
596 /*******************************************************************
597 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
599 *******************************************************************/
601 int file_ntimes(connection_struct
*conn
, const char *fname
, const struct timespec ts
[2])
603 SMB_STRUCT_STAT sbuf
;
609 DEBUG(6, ("file_ntime: actime: %s",
610 time_to_asc(convert_timespec_to_time_t(ts
[0]))));
611 DEBUG(6, ("file_ntime: modtime: %s",
612 time_to_asc(convert_timespec_to_time_t(ts
[1]))));
614 /* Don't update the time on read-only shares */
615 /* We need this as set_filetime (which can be called on
616 close and other paths) can end up calling this function
617 without the NEED_WRITE protection. Found by :
618 Leo Weppelman <leo@wau.mis.ah.nl>
621 if (!CAN_WRITE(conn
)) {
625 if(SMB_VFS_NTIMES(conn
, fname
, ts
) == 0) {
629 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
633 if(!lp_dos_filetimes(SNUM(conn
))) {
637 /* We have permission (given by the Samba admin) to
638 break POSIX semantics and allow a user to change
639 the time on a file they don't own but can write to
643 /* Check if we have write access. */
644 if (can_write_to_file(conn
, fname
, &sbuf
)) {
645 /* We are allowed to become root and change the filetime. */
647 ret
= SMB_VFS_NTIMES(conn
, fname
, ts
);
654 /******************************************************************
655 Force a "sticky" write time on a pathname. This will always be
656 returned on all future write time queries and set on close.
657 ******************************************************************/
659 bool set_sticky_write_time_path(connection_struct
*conn
, const char *fname
,
660 struct file_id fileid
, const struct timespec mtime
)
662 if (null_timespec(mtime
)) {
666 if (!set_sticky_write_time(fileid
, mtime
)) {
673 /******************************************************************
674 Force a "sticky" write time on an fsp. This will always be
675 returned on all future write time queries and set on close.
676 ******************************************************************/
678 bool set_sticky_write_time_fsp(struct files_struct
*fsp
, const struct timespec mtime
)
680 fsp
->write_time_forced
= true;
681 TALLOC_FREE(fsp
->update_write_time_event
);
683 return set_sticky_write_time_path(fsp
->conn
, fsp
->fsp_name
,
684 fsp
->file_id
, mtime
);
687 /******************************************************************
688 Update a write time immediately, without the 2 second delay.
689 ******************************************************************/
691 bool update_write_time(struct files_struct
*fsp
)
693 if (!set_write_time(fsp
->file_id
, timespec_current())) {
697 notify_fname(fsp
->conn
, NOTIFY_ACTION_MODIFIED
,
698 FILE_NOTIFY_CHANGE_LAST_WRITE
, fsp
->fsp_name
);