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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 static int set_sparse_flag(const SMB_STRUCT_STAT
* const sbuf
)
26 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
27 if (sbuf
->st_size
> sbuf
->st_blocks
* (SMB_OFF_T
)STAT_ST_BLOCKSIZE
) {
28 return FILE_ATTRIBUTE_SPARSE
;
34 /****************************************************************************
35 Work out whether this file is offline
36 ****************************************************************************/
38 static uint32
set_offline_flag(connection_struct
*conn
, const char *const path
)
40 if (ISDOT(path
) || ISDOTDOT(path
)) {
44 if (!lp_dmapi_support(SNUM(conn
)) || !dmapi_have_session()) {
48 return dmapi_file_flags(path
);
51 /****************************************************************************
52 Change a dos mode to a unix mode.
53 Base permission for files:
54 if creating file and inheriting (i.e. parent_dir != NULL)
55 apply read/write bits from parent directory.
57 everybody gets read bit set
58 dos readonly is represented in unix by removing everyone's write bit
59 dos archive is represented in unix by the user's execute bit
60 dos system is represented in unix by the group's execute bit
61 dos hidden is represented in unix by the other's execute bit
63 Then apply create mask,
66 Base permission for directories:
67 dos directory is represented in unix by unix's dir bit and the exec bit
69 Then apply create mask,
72 ****************************************************************************/
74 mode_t
unix_mode(connection_struct
*conn
, int dosmode
, const char *fname
,
75 const char *inherit_from_dir
)
77 mode_t result
= (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
78 mode_t dir_mode
= 0; /* Mode of the inherit_from directory if
81 if (!lp_store_dos_attributes(SNUM(conn
)) && IS_DOS_READONLY(dosmode
)) {
82 result
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
85 if (fname
&& (inherit_from_dir
!= NULL
)
86 && lp_inherit_perms(SNUM(conn
))) {
89 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname
,
91 if (SMB_VFS_STAT(conn
, inherit_from_dir
, &sbuf
) != 0) {
92 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname
,
93 inherit_from_dir
, strerror(errno
)));
94 return(0); /* *** shouldn't happen! *** */
97 /* Save for later - but explicitly remove setuid bit for safety. */
98 dir_mode
= sbuf
.st_mode
& ~S_ISUID
;
99 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname
,(int)dir_mode
));
104 if (IS_DOS_DIR(dosmode
)) {
105 /* We never make directories read only for the owner as under DOS a user
106 can always create a file in a read-only directory. */
107 result
|= (S_IFDIR
| S_IWUSR
);
110 /* Inherit mode of parent directory. */
113 /* Provisionally add all 'x' bits */
114 result
|= (S_IXUSR
| S_IXGRP
| S_IXOTH
);
116 /* Apply directory mask */
117 result
&= lp_dir_mask(SNUM(conn
));
118 /* Add in force bits */
119 result
|= lp_force_dir_mode(SNUM(conn
));
122 if (lp_map_archive(SNUM(conn
)) && IS_DOS_ARCHIVE(dosmode
))
125 if (lp_map_system(SNUM(conn
)) && IS_DOS_SYSTEM(dosmode
))
128 if (lp_map_hidden(SNUM(conn
)) && IS_DOS_HIDDEN(dosmode
))
132 /* Inherit 666 component of parent directory mode */
133 result
|= dir_mode
& (S_IRUSR
| S_IRGRP
| S_IROTH
| S_IWUSR
| S_IWGRP
| S_IWOTH
);
135 /* Apply mode mask */
136 result
&= lp_create_mask(SNUM(conn
));
137 /* Add in force bits */
138 result
|= lp_force_create_mode(SNUM(conn
));
142 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname
,(int)result
));
146 /****************************************************************************
147 Change a unix mode to a dos mode.
148 ****************************************************************************/
150 static uint32
dos_mode_from_sbuf(connection_struct
*conn
, const char *path
, SMB_STRUCT_STAT
*sbuf
)
153 enum mapreadonly_options ro_opts
= (enum mapreadonly_options
)lp_map_readonly(SNUM(conn
));
155 if (ro_opts
== MAP_READONLY_YES
) {
156 /* Original Samba method - map inverse of user "w" bit. */
157 if ((sbuf
->st_mode
& S_IWUSR
) == 0) {
160 } else if (ro_opts
== MAP_READONLY_PERMISSIONS
) {
161 /* Check actual permissions for read-only. */
162 if (!can_write_to_file(conn
, path
, sbuf
)) {
165 } /* Else never set the readonly bit. */
167 if (MAP_ARCHIVE(conn
) && ((sbuf
->st_mode
& S_IXUSR
) != 0))
170 if (MAP_SYSTEM(conn
) && ((sbuf
->st_mode
& S_IXGRP
) != 0))
173 if (MAP_HIDDEN(conn
) && ((sbuf
->st_mode
& S_IXOTH
) != 0))
176 if (S_ISDIR(sbuf
->st_mode
))
177 result
= aDIR
| (result
& aRONLY
);
179 result
|= set_sparse_flag(sbuf
);
183 if (S_ISLNK(sbuf
->st_mode
) && S_ISDIR(sbuf
->st_mode
))
188 DEBUG(8,("dos_mode_from_sbuf returning "));
190 if (result
& aHIDDEN
) DEBUG(8, ("h"));
191 if (result
& aRONLY
) DEBUG(8, ("r"));
192 if (result
& aSYSTEM
) DEBUG(8, ("s"));
193 if (result
& aDIR
) DEBUG(8, ("d"));
194 if (result
& aARCH
) DEBUG(8, ("a"));
200 /****************************************************************************
201 Get DOS attributes from an EA.
202 ****************************************************************************/
204 static BOOL
get_ea_dos_attribute(connection_struct
*conn
, const char *path
,SMB_STRUCT_STAT
*sbuf
, uint32
*pattr
)
208 unsigned int dosattr
;
210 if (!lp_store_dos_attributes(SNUM(conn
))) {
214 /* Don't reset pattr to zero as we may already have filename-based attributes we
217 sizeret
= SMB_VFS_GETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, sizeof(attrstr
));
219 #if defined(ENOTSUP) && defined(ENOATTR)
220 if ((errno
!= ENOTSUP
) && (errno
!= ENOATTR
) && (errno
!= EACCES
) && (errno
!= EPERM
)) {
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
);
228 /* Null terminate string. */
229 attrstr
[sizeret
] = 0;
230 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path
, attrstr
));
232 if (sizeret
< 2 || attrstr
[0] != '0' || attrstr
[1] != 'x' ||
233 sscanf(attrstr
, "%x", &dosattr
) != 1) {
234 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path
, attrstr
));
238 if (S_ISDIR(sbuf
->st_mode
)) {
241 *pattr
= (uint32
)(dosattr
& SAMBA_ATTRIBUTES_MASK
);
243 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr
));
245 if (dosattr
& aHIDDEN
) DEBUG(8, ("h"));
246 if (dosattr
& aRONLY
) DEBUG(8, ("r"));
247 if (dosattr
& aSYSTEM
) DEBUG(8, ("s"));
248 if (dosattr
& aDIR
) DEBUG(8, ("d"));
249 if (dosattr
& aARCH
) DEBUG(8, ("a"));
256 /****************************************************************************
257 Set DOS attributes in an EA.
258 ****************************************************************************/
260 static BOOL
set_ea_dos_attribute(connection_struct
*conn
, const char *path
, SMB_STRUCT_STAT
*sbuf
, uint32 dosmode
)
263 files_struct
*fsp
= NULL
;
266 if (!lp_store_dos_attributes(SNUM(conn
))) {
270 snprintf(attrstr
, sizeof(attrstr
)-1, "0x%x", dosmode
& SAMBA_ATTRIBUTES_MASK
);
271 if (SMB_VFS_SETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, strlen(attrstr
), 0) == -1) {
272 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
275 || errno
== ENOTSUP
) {
279 set_store_dos_attributes(SNUM(conn
), False
);
284 /* We want DOS semantics, ie allow non owner with write permission to change the
285 bits on a file. Just like file_ntimes below.
288 /* Check if we have write access. */
289 if(!CAN_WRITE(conn
) || !lp_dos_filemode(SNUM(conn
)))
293 * We need to open the file with write access whilst
294 * still in our current user context. This ensures we
295 * are not violating security in doing the setxattr.
298 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
,path
,sbuf
,&fsp
)))
301 if (SMB_VFS_SETXATTR(conn
, path
, SAMBA_XATTR_DOS_ATTRIB
, attrstr
, strlen(attrstr
), 0) == 0) {
305 close_file_fchmod(fsp
);
308 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr
, path
));
312 /****************************************************************************
313 Change a unix mode to a dos mode for an ms dfs link.
314 ****************************************************************************/
316 uint32
dos_mode_msdfs(connection_struct
*conn
, const char *path
,SMB_STRUCT_STAT
*sbuf
)
320 DEBUG(8,("dos_mode_msdfs: %s\n", path
));
322 if (!VALID_STAT(*sbuf
)) {
326 /* First do any modifications that depend on the path name. */
327 /* hide files with a name starting with a . */
328 if (lp_hide_dot_files(SNUM(conn
))) {
329 const char *p
= strrchr_m(path
,'/');
336 if (p
[0] == '.' && p
[1] != '.' && p
[1] != 0) {
341 result
|= dos_mode_from_sbuf(conn
, path
, sbuf
);
343 /* Optimization : Only call is_hidden_path if it's not already
345 if (!(result
& aHIDDEN
) && IS_HIDDEN_PATH(conn
,path
)) {
349 DEBUG(8,("dos_mode_msdfs returning "));
351 if (result
& aHIDDEN
) DEBUG(8, ("h"));
352 if (result
& aRONLY
) DEBUG(8, ("r"));
353 if (result
& aSYSTEM
) DEBUG(8, ("s"));
354 if (result
& aDIR
) DEBUG(8, ("d"));
355 if (result
& aARCH
) DEBUG(8, ("a"));
356 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
363 /****************************************************************************
364 Change a unix mode to a dos mode.
365 ****************************************************************************/
367 uint32
dos_mode(connection_struct
*conn
, const char *path
,SMB_STRUCT_STAT
*sbuf
)
371 DEBUG(8,("dos_mode: %s\n", path
));
373 if (!VALID_STAT(*sbuf
)) {
377 /* First do any modifications that depend on the path name. */
378 /* hide files with a name starting with a . */
379 if (lp_hide_dot_files(SNUM(conn
))) {
380 const char *p
= strrchr_m(path
,'/');
387 if (p
[0] == '.' && p
[1] != '.' && p
[1] != 0) {
392 /* Get the DOS attributes from an EA by preference. */
393 if (get_ea_dos_attribute(conn
, path
, sbuf
, &result
)) {
394 result
|= set_sparse_flag(sbuf
);
396 result
|= dos_mode_from_sbuf(conn
, path
, sbuf
);
399 if (S_ISREG(sbuf
->st_mode
)) {
400 result
|= set_offline_flag(conn
, path
);
403 /* Optimization : Only call is_hidden_path if it's not already
405 if (!(result
& aHIDDEN
) && IS_HIDDEN_PATH(conn
,path
)) {
409 DEBUG(8,("dos_mode returning "));
411 if (result
& aHIDDEN
) DEBUG(8, ("h"));
412 if (result
& aRONLY
) DEBUG(8, ("r"));
413 if (result
& aSYSTEM
) DEBUG(8, ("s"));
414 if (result
& aDIR
) DEBUG(8, ("d"));
415 if (result
& aARCH
) DEBUG(8, ("a"));
416 if (result
& FILE_ATTRIBUTE_SPARSE
) DEBUG(8, ("[sparse]"));
423 /*******************************************************************
424 chmod a file - but preserve some bits.
425 ********************************************************************/
427 int file_set_dosmode(connection_struct
*conn
, const char *fname
,
428 uint32 dosmode
, SMB_STRUCT_STAT
*st
,
429 const char *parent_dir
)
437 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
438 dosmode
&= SAMBA_ATTRIBUTES_MASK
;
440 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode
, fname
));
443 SET_STAT_INVALID(st1
);
447 if (!VALID_STAT(*st
)) {
448 if (SMB_VFS_STAT(conn
,fname
,st
))
452 unixmode
= st
->st_mode
;
454 get_acl_group_bits(conn
, fname
, &st
->st_mode
);
456 if (S_ISDIR(st
->st_mode
))
461 if (dos_mode(conn
,fname
,st
) == dosmode
) {
462 st
->st_mode
= unixmode
;
466 /* Store the DOS attributes in an EA by preference. */
467 if (set_ea_dos_attribute(conn
, fname
, st
, dosmode
)) {
468 st
->st_mode
= unixmode
;
472 unixmode
= unix_mode(conn
,dosmode
,fname
, parent_dir
);
474 /* preserve the s bits */
475 mask
|= (S_ISUID
| S_ISGID
);
477 /* preserve the t bit */
482 /* possibly preserve the x bits */
483 if (!MAP_ARCHIVE(conn
))
485 if (!MAP_SYSTEM(conn
))
487 if (!MAP_HIDDEN(conn
))
490 unixmode
|= (st
->st_mode
& mask
);
492 /* if we previously had any r bits set then leave them alone */
493 if ((tmp
= st
->st_mode
& (S_IRUSR
|S_IRGRP
|S_IROTH
))) {
494 unixmode
&= ~(S_IRUSR
|S_IRGRP
|S_IROTH
);
498 /* if we previously had any w bits set then leave them alone
499 whilst adding in the new w bits, if the new mode is not rdonly */
500 if (!IS_DOS_READONLY(dosmode
)) {
501 unixmode
|= (st
->st_mode
& (S_IWUSR
|S_IWGRP
|S_IWOTH
));
504 if ((ret
= SMB_VFS_CHMOD(conn
,fname
,unixmode
)) == 0) {
505 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
506 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
507 st
->st_mode
= unixmode
;
511 if((errno
!= EPERM
) && (errno
!= EACCES
))
514 if(!lp_dos_filemode(SNUM(conn
)))
517 /* We want DOS semantics, ie allow non owner with write permission to change the
518 bits on a file. Just like file_ntimes below.
521 /* Check if we have write access. */
522 if (CAN_WRITE(conn
)) {
524 * We need to open the file with write access whilst
525 * still in our current user context. This ensures we
526 * are not violating security in doing the fchmod.
527 * This file open does *not* break any oplocks we are
528 * holding. We need to review this.... may need to
529 * break batch oplocks open by others. JRA.
532 if (!NT_STATUS_IS_OK(open_file_fchmod(conn
,fname
,st
,&fsp
)))
535 ret
= SMB_VFS_FCHMOD(fsp
, fsp
->fh
->fd
, unixmode
);
537 close_file_fchmod(fsp
);
538 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
539 FILE_NOTIFY_CHANGE_ATTRIBUTES
, fname
);
541 st
->st_mode
= unixmode
;
548 /*******************************************************************
549 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
551 *******************************************************************/
553 int file_ntimes(connection_struct
*conn
, const char *fname
, const struct timespec ts
[2])
555 SMB_STRUCT_STAT sbuf
;
561 /* Don't update the time on read-only shares */
562 /* We need this as set_filetime (which can be called on
563 close and other paths) can end up calling this function
564 without the NEED_WRITE protection. Found by :
565 Leo Weppelman <leo@wau.mis.ah.nl>
568 if (!CAN_WRITE(conn
)) {
572 if(SMB_VFS_NTIMES(conn
, fname
, ts
) == 0) {
576 if((errno
!= EPERM
) && (errno
!= EACCES
)) {
580 if(!lp_dos_filetimes(SNUM(conn
))) {
584 /* We have permission (given by the Samba admin) to
585 break POSIX semantics and allow a user to change
586 the time on a file they don't own but can write to
590 /* Check if we have write access. */
591 if (can_write_to_file(conn
, fname
, &sbuf
)) {
592 /* We are allowed to become root and change the filetime. */
594 ret
= SMB_VFS_NTIMES(conn
, fname
, ts
);
601 /*******************************************************************
602 Change a filetime - possibly allowing DOS semantics.
603 *******************************************************************/
605 BOOL
set_filetime(connection_struct
*conn
, const char *fname
,
606 const struct timespec mtime
)
608 struct timespec ts
[2];
610 if (null_timespec(mtime
)) {
614 ts
[1] = mtime
; /* mtime. */
615 ts
[0] = ts
[1]; /* atime. */
617 if (file_ntimes(conn
, fname
, ts
)) {
618 DEBUG(4,("set_filetime(%s) failed: %s\n",fname
,strerror(errno
)));
622 notify_fname(conn
, NOTIFY_ACTION_MODIFIED
,
623 FILE_NOTIFY_CHANGE_LAST_WRITE
, fname
);