root/source3/smbd/dosmode.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_sparse_flag
  2. set_link_read_only_flag
  3. unix_mode
  4. dos_mode_from_sbuf
  5. get_ea_dos_attribute
  6. set_ea_dos_attribute
  7. dos_mode_msdfs
  8. dos_attributes_to_stat_dos_flags
  9. get_stat_dos_flags
  10. set_stat_dos_flags
  11. dos_mode
  12. file_set_dosmode
  13. file_ntimes
  14. set_sticky_write_time_path
  15. set_sticky_write_time_fsp
  16. update_write_time

   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 
  23 static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
     /* [<][>][^][v][top][bottom][index][help] */
  24 {
  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;
  28         }
  29 #endif
  30         return 0;
  31 }
  32 
  33 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
     /* [<][>][^][v][top][bottom][index][help] */
  34 {
  35 #ifdef S_ISLNK
  36 #if LINKS_READ_ONLY
  37         if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
  38                 return aRONLY;
  39 #endif
  40 #endif
  41         return 0;
  42 }
  43 
  44 /****************************************************************************
  45  Change a dos mode to a unix mode.
  46     Base permission for files:
  47          if creating file and inheriting (i.e. parent_dir != NULL)
  48            apply read/write bits from parent directory.
  49          else   
  50            everybody gets read bit set
  51          dos readonly is represented in unix by removing everyone's write bit
  52          dos archive is represented in unix by the user's execute bit
  53          dos system is represented in unix by the group's execute bit
  54          dos hidden is represented in unix by the other's execute bit
  55          if !inheriting {
  56            Then apply create mask,
  57            then add force bits.
  58          }
  59     Base permission for directories:
  60          dos directory is represented in unix by unix's dir bit and the exec bit
  61          if !inheriting {
  62            Then apply create mask,
  63            then add force bits.
  64          }
  65 ****************************************************************************/
  66 
  67 mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
  68                  const char *inherit_from_dir)
  69 {
  70         mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
  71         mode_t dir_mode = 0; /* Mode of the inherit_from directory if
  72                               * inheriting. */
  73 
  74         if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
  75                 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
  76         }
  77 
  78         if (fname && (inherit_from_dir != NULL)
  79             && lp_inherit_perms(SNUM(conn))) {
  80                 SMB_STRUCT_STAT sbuf;
  81 
  82                 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname,
  83                           inherit_from_dir));
  84                 if (SMB_VFS_STAT(conn, inherit_from_dir, &sbuf) != 0) {
  85                         DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname,
  86                                  inherit_from_dir, strerror(errno)));
  87                         return(0);      /* *** shouldn't happen! *** */
  88                 }
  89 
  90                 /* Save for later - but explicitly remove setuid bit for safety. */
  91                 dir_mode = sbuf.st_mode & ~S_ISUID;
  92                 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
  93                 /* Clear "result" */
  94                 result = 0;
  95         } 
  96 
  97         if (IS_DOS_DIR(dosmode)) {
  98                 /* We never make directories read only for the owner as under DOS a user
  99                 can always create a file in a read-only directory. */
 100                 result |= (S_IFDIR | S_IWUSR);
 101 
 102                 if (dir_mode) {
 103                         /* Inherit mode of parent directory. */
 104                         result |= dir_mode;
 105                 } else {
 106                         /* Provisionally add all 'x' bits */
 107                         result |= (S_IXUSR | S_IXGRP | S_IXOTH);                 
 108 
 109                         /* Apply directory mask */
 110                         result &= lp_dir_mask(SNUM(conn));
 111                         /* Add in force bits */
 112                         result |= lp_force_dir_mode(SNUM(conn));
 113                 }
 114         } else { 
 115                 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
 116                         result |= S_IXUSR;
 117 
 118                 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
 119                         result |= S_IXGRP;
 120  
 121                 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
 122                         result |= S_IXOTH;  
 123 
 124                 if (dir_mode) {
 125                         /* Inherit 666 component of parent directory mode */
 126                         result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
 127                 } else {
 128                         /* Apply mode mask */
 129                         result &= lp_create_mask(SNUM(conn));
 130                         /* Add in force bits */
 131                         result |= lp_force_create_mode(SNUM(conn));
 132                 }
 133         }
 134 
 135         DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result ));
 136         return(result);
 137 }
 138 
 139 /****************************************************************************
 140  Change a unix mode to a dos mode.
 141 ****************************************************************************/
 142 
 143 static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
     /* [<][>][^][v][top][bottom][index][help] */
 144 {
 145         int result = 0;
 146         enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
 147 
 148         if (ro_opts == MAP_READONLY_YES) {
 149                 /* Original Samba method - map inverse of user "w" bit. */
 150                 if ((sbuf->st_mode & S_IWUSR) == 0) {
 151                         result |= aRONLY;
 152                 }
 153         } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
 154                 /* Check actual permissions for read-only. */
 155                 if (!can_write_to_file(conn, path, sbuf)) {
 156                         result |= aRONLY;
 157                 }
 158         } /* Else never set the readonly bit. */
 159 
 160         if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
 161                 result |= aARCH;
 162 
 163         if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
 164                 result |= aSYSTEM;
 165         
 166         if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
 167                 result |= aHIDDEN;   
 168   
 169         if (S_ISDIR(sbuf->st_mode))
 170                 result = aDIR | (result & aRONLY);
 171 
 172         result |= set_sparse_flag(sbuf);
 173         result |= set_link_read_only_flag(sbuf);
 174 
 175         DEBUG(8,("dos_mode_from_sbuf returning "));
 176 
 177         if (result & aHIDDEN) DEBUG(8, ("h"));
 178         if (result & aRONLY ) DEBUG(8, ("r"));
 179         if (result & aSYSTEM) DEBUG(8, ("s"));
 180         if (result & aDIR   ) DEBUG(8, ("d"));
 181         if (result & aARCH  ) DEBUG(8, ("a"));
 182         
 183         DEBUG(8,("\n"));
 184         return result;
 185 }
 186 
 187 /****************************************************************************
 188  Get DOS attributes from an EA.
 189 ****************************************************************************/
 190 
 191 static bool get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr)
     /* [<][>][^][v][top][bottom][index][help] */
 192 {
 193         ssize_t sizeret;
 194         fstring attrstr;
 195         unsigned int dosattr;
 196 
 197         if (!lp_store_dos_attributes(SNUM(conn))) {
 198                 return False;
 199         }
 200 
 201         /* Don't reset pattr to zero as we may already have filename-based attributes we
 202            need to preserve. */
 203 
 204         sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr));
 205         if (sizeret == -1) {
 206                 if (errno == ENOSYS
 207 #if defined(ENOTSUP)
 208                         || errno == ENOTSUP) {
 209 #else
 210                                 ) {
 211 #endif
 212                         DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
 213                                 path, strerror(errno) ));
 214                         set_store_dos_attributes(SNUM(conn), False);
 215                 }
 216                 return False;
 217         }
 218         /* Null terminate string. */
 219         attrstr[sizeret] = 0;
 220         DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr));
 221 
 222         if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
 223                         sscanf(attrstr, "%x", &dosattr) != 1) {
 224                 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
 225                 return False;
 226         }
 227 
 228         if (S_ISDIR(sbuf->st_mode)) {
 229                 dosattr |= aDIR;
 230         }
 231         *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
 232 
 233         DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
 234 
 235         if (dosattr & aHIDDEN) DEBUG(8, ("h"));
 236         if (dosattr & aRONLY ) DEBUG(8, ("r"));
 237         if (dosattr & aSYSTEM) DEBUG(8, ("s"));
 238         if (dosattr & aDIR   ) DEBUG(8, ("d"));
 239         if (dosattr & aARCH  ) DEBUG(8, ("a"));
 240         
 241         DEBUG(8,("\n"));
 242 
 243         return True;
 244 }
 245 
 246 /****************************************************************************
 247  Set DOS attributes in an EA.
 248 ****************************************************************************/
 249 
 250 static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
     /* [<][>][^][v][top][bottom][index][help] */
 251 {
 252         fstring attrstr;
 253         files_struct *fsp = NULL;
 254         bool ret = False;
 255 
 256         if (!lp_store_dos_attributes(SNUM(conn))) {
 257                 return False;
 258         }
 259 
 260         snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
 261         if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
 262                 if((errno != EPERM) && (errno != EACCES)) {
 263                         if (errno == ENOSYS
 264 #if defined(ENOTSUP)
 265                                 || errno == ENOTSUP) {
 266 #else
 267                                 ) {
 268 #endif
 269                                 DEBUG(1,("set_ea_dos_attributes: Cannot set attribute EA on file %s: Error = %s\n",
 270                                         path, strerror(errno) ));
 271                                 set_store_dos_attributes(SNUM(conn), False);
 272                         }
 273                         return False;
 274                 }
 275 
 276                 /* We want DOS semantics, ie allow non owner with write permission to change the
 277                         bits on a file. Just like file_ntimes below.
 278                 */
 279 
 280                 /* Check if we have write access. */
 281                 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
 282                         return False;
 283 
 284                 /*
 285                  * We need to open the file with write access whilst
 286                  * still in our current user context. This ensures we
 287                  * are not violating security in doing the setxattr.
 288                  */
 289 
 290                 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, path, sbuf,
 291                                                       &fsp)))
 292                         return ret;
 293                 become_root();
 294                 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
 295                         ret = True;
 296                 }
 297                 unbecome_root();
 298                 close_file_fchmod(NULL, fsp);
 299                 return ret;
 300         }
 301         DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
 302         return True;
 303 }
 304 
 305 /****************************************************************************
 306  Change a unix mode to a dos mode for an ms dfs link.
 307 ****************************************************************************/
 308 
 309 uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
     /* [<][>][^][v][top][bottom][index][help] */
 310 {
 311         uint32 result = 0;
 312 
 313         DEBUG(8,("dos_mode_msdfs: %s\n", path));
 314 
 315         if (!VALID_STAT(*sbuf)) {
 316                 return 0;
 317         }
 318 
 319         /* First do any modifications that depend on the path name. */
 320         /* hide files with a name starting with a . */
 321         if (lp_hide_dot_files(SNUM(conn))) {
 322                 const char *p = strrchr_m(path,'/');
 323                 if (p) {
 324                         p++;
 325                 } else {
 326                         p = path;
 327                 }
 328 
 329                 /* Only . and .. are not hidden. */
 330                 if (p[0] == '.' && !((p[1] == '\0') ||
 331                                 (p[1] == '.' && p[2] == '\0'))) {
 332                         result |= aHIDDEN;
 333                 }
 334         }
 335         
 336         result |= dos_mode_from_sbuf(conn, path, sbuf);
 337 
 338         /* Optimization : Only call is_hidden_path if it's not already
 339            hidden. */
 340         if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
 341                 result |= aHIDDEN;
 342         }
 343 
 344         DEBUG(8,("dos_mode_msdfs returning "));
 345 
 346         if (result & aHIDDEN) DEBUG(8, ("h"));
 347         if (result & aRONLY ) DEBUG(8, ("r"));
 348         if (result & aSYSTEM) DEBUG(8, ("s"));
 349         if (result & aDIR   ) DEBUG(8, ("d"));
 350         if (result & aARCH  ) DEBUG(8, ("a"));
 351         if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
 352         
 353         DEBUG(8,("\n"));
 354 
 355         return(result);
 356 }
 357 
 358 #ifdef HAVE_STAT_DOS_FLAGS
 359 /****************************************************************************
 360  Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
 361 ****************************************************************************/
 362 
 363 int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
     /* [<][>][^][v][top][bottom][index][help] */
 364 {
 365         uint32_t dos_stat_flags = 0;
 366 
 367         if (dosmode & aARCH)
 368                 dos_stat_flags |= UF_DOS_ARCHIVE;
 369         if (dosmode & aHIDDEN)
 370                 dos_stat_flags |= UF_DOS_HIDDEN;
 371         if (dosmode & aRONLY)
 372                 dos_stat_flags |= UF_DOS_RO;
 373         if (dosmode & aSYSTEM)
 374                 dos_stat_flags |= UF_DOS_SYSTEM;
 375         if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
 376                 dos_stat_flags |= UF_DOS_NOINDEX;
 377 
 378         return dos_stat_flags;
 379 }
 380 
 381 /****************************************************************************
 382  Gets DOS attributes, accessed via st_flags in the stat struct.
 383 ****************************************************************************/
 384 
 385 static bool get_stat_dos_flags(connection_struct *conn,
     /* [<][>][^][v][top][bottom][index][help] */
 386                                const char *fname,
 387                                const SMB_STRUCT_STAT *sbuf,
 388                                uint32_t *dosmode)
 389 {
 390         SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
 391         SMB_ASSERT(dosmode);
 392 
 393         if (!lp_store_dos_attributes(SNUM(conn))) {
 394                 return false;
 395         }
 396 
 397         DEBUG(5, ("Getting stat dos attributes for %s.\n", fname));
 398 
 399         if (sbuf->st_flags & UF_DOS_ARCHIVE)
 400                 *dosmode |= aARCH;
 401         if (sbuf->st_flags & UF_DOS_HIDDEN)
 402                 *dosmode |= aHIDDEN;
 403         if (sbuf->st_flags & UF_DOS_RO)
 404                 *dosmode |= aRONLY;
 405         if (sbuf->st_flags & UF_DOS_SYSTEM)
 406                 *dosmode |= aSYSTEM;
 407         if (sbuf->st_flags & UF_DOS_NOINDEX)
 408                 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
 409         if (S_ISDIR(sbuf->st_mode))
 410                 *dosmode |= aDIR;
 411 
 412         *dosmode |= set_sparse_flag(sbuf);
 413         *dosmode |= set_link_read_only_flag(sbuf);
 414 
 415         return true;
 416 }
 417 
 418 /****************************************************************************
 419  Sets DOS attributes, stored in st_flags of the inode.
 420 ****************************************************************************/
 421 
 422 static bool set_stat_dos_flags(connection_struct *conn,
     /* [<][>][^][v][top][bottom][index][help] */
 423                                 const char *fname,
 424                                 SMB_STRUCT_STAT *sbuf,
 425                                 uint32_t dosmode,
 426                                 bool *attributes_changed)
 427 {
 428         uint32_t new_flags = 0;
 429         int error = 0;
 430 
 431         SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
 432         SMB_ASSERT(attributes_changed);
 433 
 434         *attributes_changed = false;
 435 
 436         if (!lp_store_dos_attributes(SNUM(conn))) {
 437                 return false;
 438         }
 439 
 440         DEBUG(5, ("Setting stat dos attributes for %s.\n", fname));
 441 
 442         new_flags = (sbuf->st_flags & ~UF_DOS_FLAGS) |
 443                      dos_attributes_to_stat_dos_flags(dosmode);
 444 
 445         /* Return early if no flags changed. */
 446         if (new_flags == sbuf->st_flags)
 447                 return true;
 448 
 449         DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
 450                   sbuf->st_flags));
 451 
 452         /* Set new flags with chflags. */
 453         error = SMB_VFS_CHFLAGS(conn, fname, new_flags);
 454         if (error) {
 455                 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
 456                           "file %s! errno=%d\n", new_flags, fname, errno));
 457                 return false;
 458         }
 459 
 460         *attributes_changed = true;
 461         return true;
 462 }
 463 #endif /* HAVE_STAT_DOS_FLAGS */
 464 
 465 /****************************************************************************
 466  Change a unix mode to a dos mode.
 467 ****************************************************************************/
 468 
 469 uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
     /* [<][>][^][v][top][bottom][index][help] */
 470 {
 471         uint32 result = 0;
 472         bool offline, used_stat_dos_flags = false;
 473 
 474         DEBUG(8,("dos_mode: %s\n", path));
 475 
 476         if (!VALID_STAT(*sbuf)) {
 477                 return 0;
 478         }
 479 
 480         /* First do any modifications that depend on the path name. */
 481         /* hide files with a name starting with a . */
 482         if (lp_hide_dot_files(SNUM(conn))) {
 483                 const char *p = strrchr_m(path,'/');
 484                 if (p) {
 485                         p++;
 486                 } else {
 487                         p = path;
 488                 }
 489 
 490                 /* Only . and .. are not hidden. */
 491                 if (p[0] == '.' && !((p[1] == '\0') ||
 492                                 (p[1] == '.' && p[2] == '\0'))) {
 493                         result |= aHIDDEN;
 494                 }
 495         }
 496         
 497 #ifdef HAVE_STAT_DOS_FLAGS
 498         used_stat_dos_flags = get_stat_dos_flags(conn, path, sbuf, &result);
 499 #endif
 500         if (!used_stat_dos_flags) {
 501                 /* Get the DOS attributes from an EA by preference. */
 502                 if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
 503                         result |= set_sparse_flag(sbuf);
 504                 } else {
 505                         result |= dos_mode_from_sbuf(conn, path, sbuf);
 506                 }
 507         }
 508 
 509         
 510         offline = SMB_VFS_IS_OFFLINE(conn, path, sbuf);
 511         if (S_ISREG(sbuf->st_mode) && offline) {
 512                 result |= FILE_ATTRIBUTE_OFFLINE;
 513         }
 514 
 515         /* Optimization : Only call is_hidden_path if it's not already
 516            hidden. */
 517         if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
 518                 result |= aHIDDEN;
 519         }
 520 
 521         DEBUG(8,("dos_mode returning "));
 522 
 523         if (result & aHIDDEN) DEBUG(8, ("h"));
 524         if (result & aRONLY ) DEBUG(8, ("r"));
 525         if (result & aSYSTEM) DEBUG(8, ("s"));
 526         if (result & aDIR   ) DEBUG(8, ("d"));
 527         if (result & aARCH  ) DEBUG(8, ("a"));
 528         if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
 529         
 530         DEBUG(8,("\n"));
 531 
 532         return(result);
 533 }
 534 
 535 /*******************************************************************
 536  chmod a file - but preserve some bits.
 537 ********************************************************************/
 538 
 539 int file_set_dosmode(connection_struct *conn, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 540                      uint32 dosmode, SMB_STRUCT_STAT *st,
 541                      const char *parent_dir,
 542                      bool newfile)
 543 {
 544         SMB_STRUCT_STAT st1;
 545         int mask=0;
 546         mode_t tmp;
 547         mode_t unixmode;
 548         int ret = -1, lret = -1;
 549         uint32_t old_mode;
 550 
 551         /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
 552         dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
 553 
 554         DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
 555 
 556         if (st == NULL) {
 557                 SET_STAT_INVALID(st1);
 558                 st = &st1;
 559         }
 560 
 561         if (!VALID_STAT(*st)) {
 562                 if (SMB_VFS_STAT(conn,fname,st))
 563                         return(-1);
 564         }
 565 
 566         unixmode = st->st_mode;
 567 
 568         get_acl_group_bits(conn, fname, &st->st_mode);
 569 
 570         if (S_ISDIR(st->st_mode))
 571                 dosmode |= aDIR;
 572         else
 573                 dosmode &= ~aDIR;
 574 
 575         old_mode = dos_mode(conn,fname,st);
 576         
 577         if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
 578                 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
 579                         lret = SMB_VFS_SET_OFFLINE(conn, fname);
 580                         if (lret == -1) {
 581                                 DEBUG(0, ("set_dos_mode: client has asked to set "
 582                                           "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
 583                                           "an error while setting it or it is not supported.\n",
 584                                           parent_dir, fname));
 585                         }
 586                 }
 587         }
 588 
 589         dosmode  &= ~FILE_ATTRIBUTE_OFFLINE;
 590         old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
 591 
 592         if (old_mode == dosmode) {
 593                 st->st_mode = unixmode;
 594                 return(0);
 595         }
 596 
 597 #ifdef HAVE_STAT_DOS_FLAGS
 598         {
 599                 bool attributes_changed;
 600 
 601                 if (set_stat_dos_flags(conn, fname, st, dosmode,
 602                                        &attributes_changed))
 603                 {
 604                         if (!newfile && attributes_changed) {
 605                                 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
 606                                     FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
 607                         }
 608                         st->st_mode = unixmode;
 609                         return 0;
 610                 }
 611         }
 612 #endif
 613 
 614         /* Store the DOS attributes in an EA by preference. */
 615         if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
 616                 if (!newfile) {
 617                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
 618                                 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
 619                 }
 620                 st->st_mode = unixmode;
 621                 return 0;
 622         }
 623 
 624         unixmode = unix_mode(conn,dosmode,fname, parent_dir);
 625 
 626         /* preserve the s bits */
 627         mask |= (S_ISUID | S_ISGID);
 628 
 629         /* preserve the t bit */
 630 #ifdef S_ISVTX
 631         mask |= S_ISVTX;
 632 #endif
 633 
 634         /* possibly preserve the x bits */
 635         if (!MAP_ARCHIVE(conn))
 636                 mask |= S_IXUSR;
 637         if (!MAP_SYSTEM(conn))
 638                 mask |= S_IXGRP;
 639         if (!MAP_HIDDEN(conn))
 640                 mask |= S_IXOTH;
 641 
 642         unixmode |= (st->st_mode & mask);
 643 
 644         /* if we previously had any r bits set then leave them alone */
 645         if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
 646                 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
 647                 unixmode |= tmp;
 648         }
 649 
 650         /* if we previously had any w bits set then leave them alone 
 651                 whilst adding in the new w bits, if the new mode is not rdonly */
 652         if (!IS_DOS_READONLY(dosmode)) {
 653                 unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
 654         }
 655 
 656         ret = SMB_VFS_CHMOD(conn, fname, unixmode);
 657         if (ret == 0) {
 658                 if(!newfile || (lret != -1)) {
 659                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
 660                                      FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
 661                 }
 662                 st->st_mode = unixmode;
 663                 return 0;
 664         }
 665 
 666         if((errno != EPERM) && (errno != EACCES))
 667                 return -1;
 668 
 669         if(!lp_dos_filemode(SNUM(conn)))
 670                 return -1;
 671 
 672         /* We want DOS semantics, ie allow non owner with write permission to change the
 673                 bits on a file. Just like file_ntimes below.
 674         */
 675 
 676         /* Check if we have write access. */
 677         if (CAN_WRITE(conn)) {
 678                 /*
 679                  * We need to open the file with write access whilst
 680                  * still in our current user context. This ensures we
 681                  * are not violating security in doing the fchmod.
 682                  * This file open does *not* break any oplocks we are
 683                  * holding. We need to review this.... may need to
 684                  * break batch oplocks open by others. JRA.
 685                  */
 686                 files_struct *fsp;
 687                 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, st,
 688                                                       &fsp)))
 689                         return -1;
 690                 become_root();
 691                 ret = SMB_VFS_FCHMOD(fsp, unixmode);
 692                 unbecome_root();
 693                 close_file_fchmod(NULL, fsp);
 694                 if (!newfile) {
 695                         notify_fname(conn, NOTIFY_ACTION_MODIFIED,
 696                                 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
 697                 }
 698                 if (ret == 0) {
 699                         st->st_mode = unixmode;
 700                 }
 701         }
 702 
 703         return( ret );
 704 }
 705 
 706 /*******************************************************************
 707  Wrapper around the VFS ntimes that possibly allows DOS semantics rather
 708  than POSIX.
 709 *******************************************************************/
 710 
 711 int file_ntimes(connection_struct *conn, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 712                 struct smb_file_time *ft)
 713 {
 714         SMB_STRUCT_STAT sbuf;
 715         int ret = -1;
 716 
 717         errno = 0;
 718         ZERO_STRUCT(sbuf);
 719 
 720         DEBUG(6, ("file_ntime: actime: %s",
 721                   time_to_asc(convert_timespec_to_time_t(ft->atime))));
 722         DEBUG(6, ("file_ntime: modtime: %s",
 723                   time_to_asc(convert_timespec_to_time_t(ft->mtime))));
 724         DEBUG(6, ("file_ntime: createtime: %s",
 725                   time_to_asc(convert_timespec_to_time_t(ft->create_time))));
 726 
 727         /* Don't update the time on read-only shares */
 728         /* We need this as set_filetime (which can be called on
 729            close and other paths) can end up calling this function
 730            without the NEED_WRITE protection. Found by : 
 731            Leo Weppelman <leo@wau.mis.ah.nl>
 732         */
 733 
 734         if (!CAN_WRITE(conn)) {
 735                 return 0;
 736         }
 737 
 738         if(SMB_VFS_NTIMES(conn, fname, ft) == 0) {
 739                 return 0;
 740         }
 741 
 742         if((errno != EPERM) && (errno != EACCES)) {
 743                 return -1;
 744         }
 745 
 746         if(!lp_dos_filetimes(SNUM(conn))) {
 747                 return -1;
 748         }
 749 
 750         /* We have permission (given by the Samba admin) to
 751            break POSIX semantics and allow a user to change
 752            the time on a file they don't own but can write to
 753            (as DOS does).
 754          */
 755 
 756         /* Check if we have write access. */
 757         if (can_write_to_file(conn, fname, &sbuf)) {
 758                 /* We are allowed to become root and change the filetime. */
 759                 become_root();
 760                 ret = SMB_VFS_NTIMES(conn, fname, ft);
 761                 unbecome_root();
 762         }
 763 
 764         return ret;
 765 }
 766 
 767 /******************************************************************
 768  Force a "sticky" write time on a pathname. This will always be
 769  returned on all future write time queries and set on close.
 770 ******************************************************************/
 771 
 772 bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 773                          struct file_id fileid, const struct timespec mtime)
 774 {
 775         if (null_timespec(mtime)) {
 776                 return true;
 777         }
 778 
 779         if (!set_sticky_write_time(fileid, mtime)) {
 780                 return false;
 781         }
 782 
 783         return true;
 784 }
 785 
 786 /******************************************************************
 787  Force a "sticky" write time on an fsp. This will always be
 788  returned on all future write time queries and set on close.
 789 ******************************************************************/
 790 
 791 bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime)
     /* [<][>][^][v][top][bottom][index][help] */
 792 {
 793         fsp->write_time_forced = true;
 794         TALLOC_FREE(fsp->update_write_time_event);
 795 
 796         return set_sticky_write_time_path(fsp->conn, fsp->fsp_name,
 797                         fsp->file_id, mtime);
 798 }
 799 
 800 /******************************************************************
 801  Update a write time immediately, without the 2 second delay.
 802 ******************************************************************/
 803 
 804 bool update_write_time(struct files_struct *fsp)
     /* [<][>][^][v][top][bottom][index][help] */
 805 {
 806         if (!set_write_time(fsp->file_id, timespec_current())) {
 807                 return false;
 808         }
 809 
 810         notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
 811                         FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name);
 812 
 813         return true;
 814 }

/* [<][>][^][v][top][bottom][index][help] */