2 Unix SMB/CIFS implementation.
3 dos mode handling functions
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
25 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
26 if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) {
27 return FILE_ATTRIBUTE_SPARSE;
33 /****************************************************************************
34 Change a dos mode to a unix mode.
35 Base permission for files:
36 if creating file and inheriting
37 apply read/write bits from parent directory.
39 everybody gets read bit set
40 dos readonly is represented in unix by removing everyone's write bit
41 dos archive is represented in unix by the user's execute bit
42 dos system is represented in unix by the group's execute bit
43 dos hidden is represented in unix by the other's execute bit
45 Then apply create mask,
48 Base permission for directories:
49 dos directory is represented in unix by unix's dir bit and the exec bit
51 Then apply create mask,
54 ****************************************************************************/
56 mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname, BOOL creating_file)
58 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
59 mode_t dir_mode = 0; /* Mode of the parent directory if inheriting. */
61 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
62 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
65 if (fname && creating_file && lp_inherit_perms(SNUM(conn))) {
69 dname = parent_dirname(fname);
70 DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname));
71 if (SMB_VFS_STAT(conn,dname,&sbuf) != 0) {
72 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno)));
73 return(0); /* *** shouldn't happen! *** */
76 /* Save for later - but explicitly remove setuid bit for safety. */
77 dir_mode = sbuf.st_mode & ~S_ISUID;
78 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
83 if (IS_DOS_DIR(dosmode)) {
84 /* We never make directories read only for the owner as under DOS a user
85 can always create a file in a read-only directory. */
86 result |= (S_IFDIR | S_IWUSR);
89 /* Inherit mode of parent directory. */
92 /* Provisionally add all 'x' bits */
93 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
95 /* Apply directory mask */
96 result &= lp_dir_mask(SNUM(conn));
97 /* Add in force bits */
98 result |= lp_force_dir_mode(SNUM(conn));
101 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
104 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
107 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
111 /* Inherit 666 component of parent directory mode */
112 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
114 /* Apply mode mask */
115 result &= lp_create_mask(SNUM(conn));
116 /* Add in force bits */
117 result |= lp_force_create_mode(SNUM(conn));
121 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result ));
125 /****************************************************************************
126 Change a unix mode to a dos mode.
127 ****************************************************************************/
129 static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
132 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
134 if (ro_opts == MAP_READONLY_YES) {
135 /* Original Samba method - map inverse of user "w" bit. */
136 if ((sbuf->st_mode & S_IWUSR) == 0) {
139 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
140 /* Check actual permissions for read-only. */
141 if (!can_write_to_file(conn, path, sbuf)) {
144 } /* Else never set the readonly bit. */
146 if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
149 if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
152 if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
155 if (S_ISDIR(sbuf->st_mode))
156 result = aDIR | (result & aRONLY);
158 result |= set_sparse_flag(sbuf);
162 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
167 DEBUG(8,("dos_mode_from_sbuf returning "));
169 if (result & aHIDDEN) DEBUG(8, ("h"));
170 if (result & aRONLY ) DEBUG(8, ("r"));
171 if (result & aSYSTEM) DEBUG(8, ("s"));
172 if (result & aDIR ) DEBUG(8, ("d"));
173 if (result & aARCH ) DEBUG(8, ("a"));
179 /****************************************************************************
180 Get DOS attributes from an EA.
181 ****************************************************************************/
183 static BOOL get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr)
187 unsigned int dosattr;
189 if (!lp_store_dos_attributes(SNUM(conn))) {
193 /* Don't reset pattr to zero as we may already have filename-based attributes we
196 sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr));
198 #if defined(ENOTSUP) && defined(ENOATTR)
199 if ((errno != ENOTSUP) && (errno != ENOATTR) && (errno != EACCES)) {
200 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
201 path, strerror(errno) ));
202 set_store_dos_attributes(SNUM(conn), False);
207 /* Null terminate string. */
208 attrstr[sizeret] = 0;
209 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr));
211 if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
212 sscanf(attrstr, "%x", &dosattr) != 1) {
213 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
217 if (S_ISDIR(sbuf->st_mode)) {
220 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
222 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
224 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
225 if (dosattr & aRONLY ) DEBUG(8, ("r"));
226 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
227 if (dosattr & aDIR ) DEBUG(8, ("d"));
228 if (dosattr & aARCH ) DEBUG(8, ("a"));
235 /****************************************************************************
236 Set DOS attributes in an EA.
237 ****************************************************************************/
239 static BOOL set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
242 files_struct *fsp = NULL;
245 if (!lp_store_dos_attributes(SNUM(conn))) {
249 snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
250 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
251 if((errno != EPERM) && (errno != EACCES)) {
254 || errno == ENOTSUP) {
258 set_store_dos_attributes(SNUM(conn), False);
263 /* We want DOS semantics, ie allow non owner with write permission to change the
264 bits on a file. Just like file_utime below.
267 /* Check if we have write access. */
268 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
272 * We need to open the file with write access whilst
273 * still in our current user context. This ensures we
274 * are not violating security in doing the setxattr.
277 fsp = open_file_fchmod(conn,path,sbuf);
281 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
285 close_file_fchmod(fsp);
288 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
292 /****************************************************************************
293 Change a unix mode to a dos mode.
294 ****************************************************************************/
296 uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
300 DEBUG(8,("dos_mode: %s\n", path));
302 if (!VALID_STAT(*sbuf)) {
306 /* First do any modifications that depend on the path name. */
307 /* hide files with a name starting with a . */
308 if (lp_hide_dot_files(SNUM(conn))) {
309 const char *p = strrchr_m(path,'/');
316 if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
321 /* Get the DOS attributes from an EA by preference. */
322 if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
323 result |= set_sparse_flag(sbuf);
325 result |= dos_mode_from_sbuf(conn, path, sbuf);
328 /* Optimization : Only call is_hidden_path if it's not already
330 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
334 DEBUG(8,("dos_mode returning "));
336 if (result & aHIDDEN) DEBUG(8, ("h"));
337 if (result & aRONLY ) DEBUG(8, ("r"));
338 if (result & aSYSTEM) DEBUG(8, ("s"));
339 if (result & aDIR ) DEBUG(8, ("d"));
340 if (result & aARCH ) DEBUG(8, ("a"));
341 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
348 /*******************************************************************
349 chmod a file - but preserve some bits.
350 ********************************************************************/
352 int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode, SMB_STRUCT_STAT *st, BOOL creating_file)
360 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
361 dosmode &= SAMBA_ATTRIBUTES_MASK;
363 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
364 if (!st || (st && !VALID_STAT(*st))) {
366 if (SMB_VFS_STAT(conn,fname,st))
370 get_acl_group_bits(conn, fname, &st->st_mode);
372 if (S_ISDIR(st->st_mode))
377 if (dos_mode(conn,fname,st) == dosmode)
380 /* Store the DOS attributes in an EA by preference. */
381 if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
385 unixmode = unix_mode(conn,dosmode,fname, creating_file);
387 /* preserve the s bits */
388 mask |= (S_ISUID | S_ISGID);
390 /* preserve the t bit */
395 /* possibly preserve the x bits */
396 if (!MAP_ARCHIVE(conn))
398 if (!MAP_SYSTEM(conn))
400 if (!MAP_HIDDEN(conn))
403 unixmode |= (st->st_mode & mask);
405 /* if we previously had any r bits set then leave them alone */
406 if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
407 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
411 /* if we previously had any w bits set then leave them alone
412 whilst adding in the new w bits, if the new mode is not rdonly */
413 if (!IS_DOS_READONLY(dosmode)) {
414 unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
417 if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0)
420 if((errno != EPERM) && (errno != EACCES))
423 if(!lp_dos_filemode(SNUM(conn)))
426 /* We want DOS semantics, ie allow non owner with write permission to change the
427 bits on a file. Just like file_utime below.
430 /* Check if we have write access. */
431 if (CAN_WRITE(conn)) {
433 * We need to open the file with write access whilst
434 * still in our current user context. This ensures we
435 * are not violating security in doing the fchmod.
436 * This file open does *not* break any oplocks we are
437 * holding. We need to review this.... may need to
438 * break batch oplocks open by others. JRA.
440 files_struct *fsp = open_file_fchmod(conn,fname,st);
444 ret = SMB_VFS_FCHMOD(fsp, fsp->fh->fd, unixmode);
446 close_file_fchmod(fsp);
452 /*******************************************************************
453 Wrapper around dos_utime that possibly allows DOS semantics rather
455 *******************************************************************/
457 int file_utime(connection_struct *conn, const char *fname, struct utimbuf *times)
459 SMB_STRUCT_STAT sbuf;
465 /* Don't update the time on read-only shares */
466 /* We need this as set_filetime (which can be called on
467 close and other paths) can end up calling this function
468 without the NEED_WRITE protection. Found by :
469 Leo Weppelman <leo@wau.mis.ah.nl>
472 if (!CAN_WRITE(conn)) {
476 if(SMB_VFS_UTIME(conn,fname, times) == 0)
479 if((errno != EPERM) && (errno != EACCES))
482 if(!lp_dos_filetimes(SNUM(conn)))
485 /* We have permission (given by the Samba admin) to
486 break POSIX semantics and allow a user to change
487 the time on a file they don't own but can write to
491 /* Check if we have write access. */
492 if (can_write_to_file(conn, fname, &sbuf)) {
493 /* We are allowed to become root and change the filetime. */
495 ret = SMB_VFS_UTIME(conn,fname, times);
502 /*******************************************************************
503 Change a filetime - possibly allowing DOS semantics.
504 *******************************************************************/
506 BOOL set_filetime(connection_struct *conn, const char *fname, time_t mtime)
508 struct utimbuf times;
510 if (null_mtime(mtime))
513 times.modtime = times.actime = mtime;
515 if (file_utime(conn, fname, ×)) {
516 DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));