Pass struct smb_request to file_new
[Samba.git] / source3 / smbd / dosmode.c
bloba5cca53bc7617f801bc33ddd1ca95f3ed113ee28
1 /*
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/>.
21 #include "includes.h"
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;
29 #endif
30 return 0;
33 /****************************************************************************
34 Change a dos mode to a unix mode.
35 Base permission for files:
36 if creating file and inheriting (i.e. parent_dir != NULL)
37 apply read/write bits from parent directory.
38 else
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
44 if !inheriting {
45 Then apply create mask,
46 then add force bits.
48 Base permission for directories:
49 dos directory is represented in unix by unix's dir bit and the exec bit
50 if !inheriting {
51 Then apply create mask,
52 then add force bits.
54 ****************************************************************************/
56 mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname,
57 const char *inherit_from_dir)
59 mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
60 mode_t dir_mode = 0; /* Mode of the inherit_from directory if
61 * inheriting. */
63 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
64 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
67 if (fname && (inherit_from_dir != NULL)
68 && lp_inherit_perms(SNUM(conn))) {
69 SMB_STRUCT_STAT sbuf;
71 DEBUG(2, ("unix_mode(%s) inheriting from %s\n", fname,
72 inherit_from_dir));
73 if (SMB_VFS_STAT(conn, inherit_from_dir, &sbuf) != 0) {
74 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n", fname,
75 inherit_from_dir, strerror(errno)));
76 return(0); /* *** shouldn't happen! *** */
79 /* Save for later - but explicitly remove setuid bit for safety. */
80 dir_mode = sbuf.st_mode & ~S_ISUID;
81 DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode));
82 /* Clear "result" */
83 result = 0;
86 if (IS_DOS_DIR(dosmode)) {
87 /* We never make directories read only for the owner as under DOS a user
88 can always create a file in a read-only directory. */
89 result |= (S_IFDIR | S_IWUSR);
91 if (dir_mode) {
92 /* Inherit mode of parent directory. */
93 result |= dir_mode;
94 } else {
95 /* Provisionally add all 'x' bits */
96 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
98 /* Apply directory mask */
99 result &= lp_dir_mask(SNUM(conn));
100 /* Add in force bits */
101 result |= lp_force_dir_mode(SNUM(conn));
103 } else {
104 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
105 result |= S_IXUSR;
107 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
108 result |= S_IXGRP;
110 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
111 result |= S_IXOTH;
113 if (dir_mode) {
114 /* Inherit 666 component of parent directory mode */
115 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
116 } else {
117 /* Apply mode mask */
118 result &= lp_create_mask(SNUM(conn));
119 /* Add in force bits */
120 result |= lp_force_create_mode(SNUM(conn));
124 DEBUG(3,("unix_mode(%s) returning 0%o\n",fname,(int)result ));
125 return(result);
128 /****************************************************************************
129 Change a unix mode to a dos mode.
130 ****************************************************************************/
132 static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
134 int result = 0;
135 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
137 if (ro_opts == MAP_READONLY_YES) {
138 /* Original Samba method - map inverse of user "w" bit. */
139 if ((sbuf->st_mode & S_IWUSR) == 0) {
140 result |= aRONLY;
142 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
143 /* Check actual permissions for read-only. */
144 if (!can_write_to_file(conn, path, sbuf)) {
145 result |= aRONLY;
147 } /* Else never set the readonly bit. */
149 if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
150 result |= aARCH;
152 if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
153 result |= aSYSTEM;
155 if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
156 result |= aHIDDEN;
158 if (S_ISDIR(sbuf->st_mode))
159 result = aDIR | (result & aRONLY);
161 result |= set_sparse_flag(sbuf);
163 #ifdef S_ISLNK
164 #if LINKS_READ_ONLY
165 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
166 result |= aRONLY;
167 #endif
168 #endif
170 DEBUG(8,("dos_mode_from_sbuf returning "));
172 if (result & aHIDDEN) DEBUG(8, ("h"));
173 if (result & aRONLY ) DEBUG(8, ("r"));
174 if (result & aSYSTEM) DEBUG(8, ("s"));
175 if (result & aDIR ) DEBUG(8, ("d"));
176 if (result & aARCH ) DEBUG(8, ("a"));
178 DEBUG(8,("\n"));
179 return result;
182 /****************************************************************************
183 Get DOS attributes from an EA.
184 ****************************************************************************/
186 static bool get_ea_dos_attribute(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf, uint32 *pattr)
188 ssize_t sizeret;
189 fstring attrstr;
190 unsigned int dosattr;
192 if (!lp_store_dos_attributes(SNUM(conn))) {
193 return False;
196 /* Don't reset pattr to zero as we may already have filename-based attributes we
197 need to preserve. */
199 sizeret = SMB_VFS_GETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr));
200 if (sizeret == -1) {
201 #if defined(ENOTSUP) && defined(ENOATTR)
202 if ((errno != ENOTSUP) && (errno != ENOATTR) && (errno != EACCES) && (errno != EPERM)) {
203 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute from EA on file %s: Error = %s\n",
204 path, strerror(errno) ));
205 set_store_dos_attributes(SNUM(conn), False);
207 #endif
208 return False;
210 /* Null terminate string. */
211 attrstr[sizeret] = 0;
212 DEBUG(10,("get_ea_dos_attribute: %s attrstr = %s\n", path, attrstr));
214 if (sizeret < 2 || attrstr[0] != '0' || attrstr[1] != 'x' ||
215 sscanf(attrstr, "%x", &dosattr) != 1) {
216 DEBUG(1,("get_ea_dos_attributes: Badly formed DOSATTRIB on file %s - %s\n", path, attrstr));
217 return False;
220 if (S_ISDIR(sbuf->st_mode)) {
221 dosattr |= aDIR;
223 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
225 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
227 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
228 if (dosattr & aRONLY ) DEBUG(8, ("r"));
229 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
230 if (dosattr & aDIR ) DEBUG(8, ("d"));
231 if (dosattr & aARCH ) DEBUG(8, ("a"));
233 DEBUG(8,("\n"));
235 return True;
238 /****************************************************************************
239 Set DOS attributes in an EA.
240 ****************************************************************************/
242 static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode)
244 fstring attrstr;
245 files_struct *fsp = NULL;
246 bool ret = False;
248 if (!lp_store_dos_attributes(SNUM(conn))) {
249 return False;
252 snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK);
253 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) {
254 if((errno != EPERM) && (errno != EACCES)) {
255 if (errno == ENOSYS
256 #if defined(ENOTSUP)
257 || errno == ENOTSUP) {
258 #else
260 #endif
261 set_store_dos_attributes(SNUM(conn), False);
263 return False;
266 /* We want DOS semantics, ie allow non owner with write permission to change the
267 bits on a file. Just like file_ntimes below.
270 /* Check if we have write access. */
271 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
272 return False;
275 * We need to open the file with write access whilst
276 * still in our current user context. This ensures we
277 * are not violating security in doing the setxattr.
280 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, path, sbuf,
281 &fsp)))
282 return ret;
283 become_root();
284 if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) {
285 ret = True;
287 unbecome_root();
288 close_file_fchmod(fsp);
289 return ret;
291 DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
292 return True;
295 /****************************************************************************
296 Change a unix mode to a dos mode for an ms dfs link.
297 ****************************************************************************/
299 uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
301 uint32 result = 0;
303 DEBUG(8,("dos_mode_msdfs: %s\n", path));
305 if (!VALID_STAT(*sbuf)) {
306 return 0;
309 /* First do any modifications that depend on the path name. */
310 /* hide files with a name starting with a . */
311 if (lp_hide_dot_files(SNUM(conn))) {
312 const char *p = strrchr_m(path,'/');
313 if (p) {
314 p++;
315 } else {
316 p = path;
319 if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
320 result |= aHIDDEN;
324 result |= dos_mode_from_sbuf(conn, path, sbuf);
326 /* Optimization : Only call is_hidden_path if it's not already
327 hidden. */
328 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
329 result |= aHIDDEN;
332 DEBUG(8,("dos_mode_msdfs returning "));
334 if (result & aHIDDEN) DEBUG(8, ("h"));
335 if (result & aRONLY ) DEBUG(8, ("r"));
336 if (result & aSYSTEM) DEBUG(8, ("s"));
337 if (result & aDIR ) DEBUG(8, ("d"));
338 if (result & aARCH ) DEBUG(8, ("a"));
339 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
341 DEBUG(8,("\n"));
343 return(result);
346 /****************************************************************************
347 Change a unix mode to a dos mode.
348 ****************************************************************************/
350 uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
352 uint32 result = 0;
353 bool offline;
355 DEBUG(8,("dos_mode: %s\n", path));
357 if (!VALID_STAT(*sbuf)) {
358 return 0;
361 /* First do any modifications that depend on the path name. */
362 /* hide files with a name starting with a . */
363 if (lp_hide_dot_files(SNUM(conn))) {
364 const char *p = strrchr_m(path,'/');
365 if (p) {
366 p++;
367 } else {
368 p = path;
371 if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
372 result |= aHIDDEN;
376 /* Get the DOS attributes from an EA by preference. */
377 if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
378 result |= set_sparse_flag(sbuf);
379 } else {
380 result |= dos_mode_from_sbuf(conn, path, sbuf);
384 offline = SMB_VFS_IS_OFFLINE(conn, path, sbuf);
385 if (S_ISREG(sbuf->st_mode) && offline) {
386 result |= FILE_ATTRIBUTE_OFFLINE;
389 /* Optimization : Only call is_hidden_path if it's not already
390 hidden. */
391 if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
392 result |= aHIDDEN;
395 DEBUG(8,("dos_mode returning "));
397 if (result & aHIDDEN) DEBUG(8, ("h"));
398 if (result & aRONLY ) DEBUG(8, ("r"));
399 if (result & aSYSTEM) DEBUG(8, ("s"));
400 if (result & aDIR ) DEBUG(8, ("d"));
401 if (result & aARCH ) DEBUG(8, ("a"));
402 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
404 DEBUG(8,("\n"));
406 return(result);
409 /*******************************************************************
410 chmod a file - but preserve some bits.
411 ********************************************************************/
413 int file_set_dosmode(connection_struct *conn, const char *fname,
414 uint32 dosmode, SMB_STRUCT_STAT *st,
415 const char *parent_dir,
416 bool newfile)
418 SMB_STRUCT_STAT st1;
419 int mask=0;
420 mode_t tmp;
421 mode_t unixmode;
422 int ret = -1, lret = -1;
423 uint32_t old_mode;
425 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
426 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
428 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
430 if (st == NULL) {
431 SET_STAT_INVALID(st1);
432 st = &st1;
435 if (!VALID_STAT(*st)) {
436 if (SMB_VFS_STAT(conn,fname,st))
437 return(-1);
440 unixmode = st->st_mode;
442 get_acl_group_bits(conn, fname, &st->st_mode);
444 if (S_ISDIR(st->st_mode))
445 dosmode |= aDIR;
446 else
447 dosmode &= ~aDIR;
449 old_mode = dos_mode(conn,fname,st);
451 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
452 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
453 lret = SMB_VFS_SET_OFFLINE(conn, fname);
454 if (lret == -1) {
455 DEBUG(0, ("set_dos_mode: client has asked to set "
456 "FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
457 "an error while setting it or it is not supported.\n",
458 parent_dir, fname));
463 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
464 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
466 if (old_mode == dosmode) {
467 st->st_mode = unixmode;
468 return(0);
471 /* Store the DOS attributes in an EA by preference. */
472 if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
473 if (!newfile) {
474 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
475 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
477 st->st_mode = unixmode;
478 return 0;
481 unixmode = unix_mode(conn,dosmode,fname, parent_dir);
483 /* preserve the s bits */
484 mask |= (S_ISUID | S_ISGID);
486 /* preserve the t bit */
487 #ifdef S_ISVTX
488 mask |= S_ISVTX;
489 #endif
491 /* possibly preserve the x bits */
492 if (!MAP_ARCHIVE(conn))
493 mask |= S_IXUSR;
494 if (!MAP_SYSTEM(conn))
495 mask |= S_IXGRP;
496 if (!MAP_HIDDEN(conn))
497 mask |= S_IXOTH;
499 unixmode |= (st->st_mode & mask);
501 /* if we previously had any r bits set then leave them alone */
502 if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
503 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
504 unixmode |= tmp;
507 /* if we previously had any w bits set then leave them alone
508 whilst adding in the new w bits, if the new mode is not rdonly */
509 if (!IS_DOS_READONLY(dosmode)) {
510 unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
513 ret = SMB_VFS_CHMOD(conn, fname, unixmode);
514 if (ret == 0) {
515 if(!newfile || (lret != -1)) {
516 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
517 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
519 st->st_mode = unixmode;
520 return 0;
523 if((errno != EPERM) && (errno != EACCES))
524 return -1;
526 if(!lp_dos_filemode(SNUM(conn)))
527 return -1;
529 /* We want DOS semantics, ie allow non owner with write permission to change the
530 bits on a file. Just like file_ntimes below.
533 /* Check if we have write access. */
534 if (CAN_WRITE(conn)) {
536 * We need to open the file with write access whilst
537 * still in our current user context. This ensures we
538 * are not violating security in doing the fchmod.
539 * This file open does *not* break any oplocks we are
540 * holding. We need to review this.... may need to
541 * break batch oplocks open by others. JRA.
543 files_struct *fsp;
544 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, st,
545 &fsp)))
546 return -1;
547 become_root();
548 ret = SMB_VFS_FCHMOD(fsp, unixmode);
549 unbecome_root();
550 close_file_fchmod(fsp);
551 if (!newfile) {
552 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
553 FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
555 if (ret == 0) {
556 st->st_mode = unixmode;
560 return( ret );
563 /*******************************************************************
564 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
565 than POSIX.
566 *******************************************************************/
568 int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2])
570 SMB_STRUCT_STAT sbuf;
571 int ret = -1;
573 errno = 0;
574 ZERO_STRUCT(sbuf);
576 DEBUG(6, ("file_ntime: actime: %s",
577 time_to_asc(convert_timespec_to_time_t(ts[0]))));
578 DEBUG(6, ("file_ntime: modtime: %s",
579 time_to_asc(convert_timespec_to_time_t(ts[1]))));
581 /* Don't update the time on read-only shares */
582 /* We need this as set_filetime (which can be called on
583 close and other paths) can end up calling this function
584 without the NEED_WRITE protection. Found by :
585 Leo Weppelman <leo@wau.mis.ah.nl>
588 if (!CAN_WRITE(conn)) {
589 return 0;
592 if(SMB_VFS_NTIMES(conn, fname, ts) == 0) {
593 return 0;
596 if((errno != EPERM) && (errno != EACCES)) {
597 return -1;
600 if(!lp_dos_filetimes(SNUM(conn))) {
601 return -1;
604 /* We have permission (given by the Samba admin) to
605 break POSIX semantics and allow a user to change
606 the time on a file they don't own but can write to
607 (as DOS does).
610 /* Check if we have write access. */
611 if (can_write_to_file(conn, fname, &sbuf)) {
612 /* We are allowed to become root and change the filetime. */
613 become_root();
614 ret = SMB_VFS_NTIMES(conn, fname, ts);
615 unbecome_root();
618 return ret;
621 /******************************************************************
622 Force a "sticky" write time on a pathname. This will always be
623 returned on all future write time queries and set on close.
624 ******************************************************************/
626 bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
627 struct file_id fileid, const struct timespec mtime)
629 if (null_timespec(mtime)) {
630 return true;
633 if (!set_sticky_write_time(fileid, mtime)) {
634 return false;
637 return true;
640 /******************************************************************
641 Force a "sticky" write time on an fsp. This will always be
642 returned on all future write time queries and set on close.
643 ******************************************************************/
645 bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime)
647 fsp->write_time_forced = true;
648 TALLOC_FREE(fsp->update_write_time_event);
650 return set_sticky_write_time_path(fsp->conn, fsp->fsp_name,
651 fsp->file_id, mtime);
654 /******************************************************************
655 Update a write time immediately, without the 2 second delay.
656 ******************************************************************/
658 bool update_write_time(struct files_struct *fsp)
660 if (!set_write_time(fsp->file_id, timespec_current())) {
661 return false;
664 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
665 FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name);
667 return true;