source: vendor/3.6.23/source3/smbd/dosmode.c

Last change on this file was 860, checked in by Silvan Scherrer, 11 years ago

Samba 3.6: updated vendor to latest version

File size: 31.0 KB
Line 
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#include "system/filesys.h"
23#include "librpc/gen_ndr/ndr_xattr.h"
24#include "../libcli/security/security.h"
25#include "smbd/smbd.h"
26
27static uint32_t filter_mode_by_protocol(uint32_t mode)
28{
29 if (get_Protocol() <= PROTOCOL_LANMAN2) {
30 DEBUG(10,("filter_mode_by_protocol: "
31 "filtering result 0x%x to 0x%x\n",
32 (unsigned int)mode,
33 (unsigned int)(mode & 0x3f) ));
34 mode &= 0x3f;
35 }
36 return mode;
37}
38
39static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
40{
41#ifdef S_ISLNK
42#if LINKS_READ_ONLY
43 if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
44 return FILE_ATTRIBUTE_READONLY;
45#endif
46#endif
47 return 0;
48}
49
50/****************************************************************************
51 Change a dos mode to a unix mode.
52 Base permission for files:
53 if creating file and inheriting (i.e. parent_dir != NULL)
54 apply read/write bits from parent directory.
55 else
56 everybody gets read bit set
57 dos readonly is represented in unix by removing everyone's write bit
58 dos archive is represented in unix by the user's execute bit
59 dos system is represented in unix by the group's execute bit
60 dos hidden is represented in unix by the other's execute bit
61 if !inheriting {
62 Then apply create mask,
63 then add force bits.
64 }
65 Base permission for directories:
66 dos directory is represented in unix by unix's dir bit and the exec bit
67 if !inheriting {
68 Then apply create mask,
69 then add force bits.
70 }
71****************************************************************************/
72
73mode_t unix_mode(connection_struct *conn, int dosmode,
74 const struct smb_filename *smb_fname,
75 const char *inherit_from_dir)
76{
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
79 * inheriting. */
80
81 if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
82 result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
83 }
84
85 if ((inherit_from_dir != NULL) && lp_inherit_perms(SNUM(conn))) {
86 struct smb_filename *smb_fname_parent = NULL;
87 NTSTATUS status;
88
89 DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
90 smb_fname_str_dbg(smb_fname),
91 inherit_from_dir));
92
93 status = create_synthetic_smb_fname(talloc_tos(),
94 inherit_from_dir, NULL,
95 NULL, &smb_fname_parent);
96 if (!NT_STATUS_IS_OK(status)) {
97 DEBUG(1,("unix_mode(%s) failed, [dir %s]: %s\n",
98 smb_fname_str_dbg(smb_fname),
99 inherit_from_dir, nt_errstr(status)));
100 return(0);
101 }
102
103 if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
104 DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
105 smb_fname_str_dbg(smb_fname),
106 inherit_from_dir, strerror(errno)));
107 TALLOC_FREE(smb_fname_parent);
108 return(0); /* *** shouldn't happen! *** */
109 }
110
111 /* Save for later - but explicitly remove setuid bit for safety. */
112 dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
113 DEBUG(2,("unix_mode(%s) inherit mode %o\n",
114 smb_fname_str_dbg(smb_fname), (int)dir_mode));
115 /* Clear "result" */
116 result = 0;
117 TALLOC_FREE(smb_fname_parent);
118 }
119
120 if (IS_DOS_DIR(dosmode)) {
121 /* We never make directories read only for the owner as under DOS a user
122 can always create a file in a read-only directory. */
123 result |= (S_IFDIR | S_IWUSR);
124
125 if (dir_mode) {
126 /* Inherit mode of parent directory. */
127 result |= dir_mode;
128 } else {
129 /* Provisionally add all 'x' bits */
130 result |= (S_IXUSR | S_IXGRP | S_IXOTH);
131
132 /* Apply directory mask */
133 result &= lp_dir_mask(SNUM(conn));
134 /* Add in force bits */
135 result |= lp_force_dir_mode(SNUM(conn));
136 }
137 } else {
138 if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
139 result |= S_IXUSR;
140
141 if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
142 result |= S_IXGRP;
143
144 if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
145 result |= S_IXOTH;
146
147 if (dir_mode) {
148 /* Inherit 666 component of parent directory mode */
149 result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
150 } else {
151 /* Apply mode mask */
152 result &= lp_create_mask(SNUM(conn));
153 /* Add in force bits */
154 result |= lp_force_create_mode(SNUM(conn));
155 }
156 }
157
158 DEBUG(3,("unix_mode(%s) returning 0%o\n", smb_fname_str_dbg(smb_fname),
159 (int)result));
160 return(result);
161}
162
163/****************************************************************************
164 Change a unix mode to a dos mode.
165****************************************************************************/
166
167static uint32 dos_mode_from_sbuf(connection_struct *conn,
168 const struct smb_filename *smb_fname)
169{
170 int result = 0;
171 enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
172
173 if (ro_opts == MAP_READONLY_YES) {
174 /* Original Samba method - map inverse of user "w" bit. */
175 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
176 result |= FILE_ATTRIBUTE_READONLY;
177 }
178 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
179 /* Check actual permissions for read-only. */
180 if (!can_write_to_file(conn, smb_fname)) {
181 result |= FILE_ATTRIBUTE_READONLY;
182 }
183 } /* Else never set the readonly bit. */
184
185 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
186 result |= FILE_ATTRIBUTE_ARCHIVE;
187
188 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
189 result |= FILE_ATTRIBUTE_SYSTEM;
190
191 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
192 result |= FILE_ATTRIBUTE_HIDDEN;
193
194 if (S_ISDIR(smb_fname->st.st_ex_mode))
195 result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
196
197 result |= set_link_read_only_flag(&smb_fname->st);
198
199 DEBUG(8,("dos_mode_from_sbuf returning "));
200
201 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
202 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
203 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
204 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
205 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
206
207 DEBUG(8,("\n"));
208 return result;
209}
210
211/****************************************************************************
212 Get DOS attributes from an EA.
213 This can also pull the create time into the stat struct inside smb_fname.
214****************************************************************************/
215
216static bool get_ea_dos_attribute(connection_struct *conn,
217 struct smb_filename *smb_fname,
218 uint32 *pattr)
219{
220 struct xattr_DOSATTRIB dosattrib;
221 enum ndr_err_code ndr_err;
222 DATA_BLOB blob;
223 ssize_t sizeret;
224 fstring attrstr;
225 uint32_t dosattr;
226
227 if (!lp_store_dos_attributes(SNUM(conn))) {
228 return False;
229 }
230
231 /* Don't reset pattr to zero as we may already have filename-based attributes we
232 need to preserve. */
233
234 sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
235 SAMBA_XATTR_DOS_ATTRIB, attrstr,
236 sizeof(attrstr));
237 if (sizeret == -1) {
238 if (errno == ENOSYS
239#if defined(ENOTSUP)
240 || errno == ENOTSUP) {
241#else
242 ) {
243#endif
244 DEBUG(1,("get_ea_dos_attribute: Cannot get attribute "
245 "from EA on file %s: Error = %s\n",
246 smb_fname_str_dbg(smb_fname),
247 strerror(errno)));
248 set_store_dos_attributes(SNUM(conn), False);
249 }
250 return False;
251 }
252
253 blob.data = (uint8_t *)attrstr;
254 blob.length = sizeret;
255
256 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
257 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
258
259 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
260 DEBUG(1,("get_ea_dos_attribute: bad ndr decode "
261 "from EA on file %s: Error = %s\n",
262 smb_fname_str_dbg(smb_fname),
263 ndr_errstr(ndr_err)));
264 return false;
265 }
266
267 DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n",
268 smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex));
269
270 switch (dosattrib.version) {
271 case 0xFFFF:
272 dosattr = dosattrib.info.compatinfoFFFF.attrib;
273 break;
274 case 1:
275 dosattr = dosattrib.info.info1.attrib;
276 if (!null_nttime(dosattrib.info.info1.create_time)) {
277 struct timespec create_time =
278 nt_time_to_unix_timespec(
279 &dosattrib.info.info1.create_time);
280
281 update_stat_ex_create_time(&smb_fname->st,
282 create_time);
283
284 DEBUG(10,("get_ea_dos_attribute: file %s case 1 "
285 "set btime %s\n",
286 smb_fname_str_dbg(smb_fname),
287 time_to_asc(convert_timespec_to_time_t(
288 create_time)) ));
289 }
290 break;
291 case 2:
292 dosattr = dosattrib.info.oldinfo2.attrib;
293 /* Don't know what flags to check for this case. */
294 break;
295 case 3:
296 dosattr = dosattrib.info.info3.attrib;
297 if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
298 !null_nttime(dosattrib.info.info3.create_time)) {
299 struct timespec create_time =
300 nt_time_to_unix_timespec(
301 &dosattrib.info.info3.create_time);
302
303 update_stat_ex_create_time(&smb_fname->st,
304 create_time);
305
306 DEBUG(10,("get_ea_dos_attribute: file %s case 3 "
307 "set btime %s\n",
308 smb_fname_str_dbg(smb_fname),
309 time_to_asc(convert_timespec_to_time_t(
310 create_time)) ));
311 }
312 break;
313 default:
314 DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on "
315 "file %s - %s\n", smb_fname_str_dbg(smb_fname),
316 attrstr));
317 return false;
318 }
319
320 if (S_ISDIR(smb_fname->st.st_ex_mode)) {
321 dosattr |= FILE_ATTRIBUTE_DIRECTORY;
322 }
323 /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
324 *pattr = (uint32)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
325
326 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
327
328 if (dosattr & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
329 if (dosattr & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
330 if (dosattr & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
331 if (dosattr & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
332 if (dosattr & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
333
334 DEBUG(8,("\n"));
335
336 return True;
337}
338
339/****************************************************************************
340 Set DOS attributes in an EA.
341 Also sets the create time.
342****************************************************************************/
343
344static bool set_ea_dos_attribute(connection_struct *conn,
345 struct smb_filename *smb_fname,
346 uint32 dosmode)
347{
348 struct xattr_DOSATTRIB dosattrib;
349 enum ndr_err_code ndr_err;
350 DATA_BLOB blob;
351
352 if (!lp_store_dos_attributes(SNUM(conn))) {
353 return False;
354 }
355
356 ZERO_STRUCT(dosattrib);
357 ZERO_STRUCT(blob);
358
359 dosattrib.version = 3;
360 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
361 XATTR_DOSINFO_CREATE_TIME;
362 dosattrib.info.info3.attrib = dosmode;
363 unix_timespec_to_nt_time(&dosattrib.info.info3.create_time,
364 smb_fname->st.st_ex_btime);
365
366 DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
367 (unsigned int)dosmode,
368 time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
369 smb_fname_str_dbg(smb_fname) ));
370
371 ndr_err = ndr_push_struct_blob(
372 &blob, talloc_tos(), &dosattrib,
373 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
374
375 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
376 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
377 ndr_errstr(ndr_err)));
378 return false;
379 }
380
381 if (blob.data == NULL || blob.length == 0) {
382 return false;
383 }
384
385 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
386 SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
387 0) == -1) {
388 bool ret = false;
389 files_struct *fsp = NULL;
390
391 if((errno != EPERM) && (errno != EACCES)) {
392 if (errno == ENOSYS
393#if defined(ENOTSUP)
394 || errno == ENOTSUP) {
395#else
396 ) {
397#endif
398 DEBUG(1,("set_ea_dos_attributes: Cannot set "
399 "attribute EA on file %s: Error = %s\n",
400 smb_fname_str_dbg(smb_fname),
401 strerror(errno) ));
402 set_store_dos_attributes(SNUM(conn), False);
403 }
404 return false;
405 }
406
407 /* We want DOS semantics, ie allow non owner with write permission to change the
408 bits on a file. Just like file_ntimes below.
409 */
410
411 /* Check if we have write access. */
412 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
413 return false;
414
415 /*
416 * We need to open the file with write access whilst
417 * still in our current user context. This ensures we
418 * are not violating security in doing the setxattr.
419 */
420
421 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname,
422 &fsp)))
423 return false;
424 become_root();
425 if (SMB_VFS_FSETXATTR(fsp,
426 SAMBA_XATTR_DOS_ATTRIB, blob.data,
427 blob.length, 0) == 0) {
428 ret = true;
429 }
430 unbecome_root();
431 close_file(NULL, fsp, NORMAL_CLOSE);
432 return ret;
433 }
434 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
435 (unsigned int)dosmode,
436 smb_fname_str_dbg(smb_fname)));
437 return true;
438}
439
440/****************************************************************************
441 Change a unix mode to a dos mode for an ms dfs link.
442****************************************************************************/
443
444uint32 dos_mode_msdfs(connection_struct *conn,
445 const struct smb_filename *smb_fname)
446{
447 uint32 result = 0;
448
449 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
450
451 if (!VALID_STAT(smb_fname->st)) {
452 return 0;
453 }
454
455 /* First do any modifications that depend on the path name. */
456 /* hide files with a name starting with a . */
457 if (lp_hide_dot_files(SNUM(conn))) {
458 const char *p = strrchr_m(smb_fname->base_name, '/');
459 if (p) {
460 p++;
461 } else {
462 p = smb_fname->base_name;
463 }
464
465 /* Only . and .. are not hidden. */
466 if (p[0] == '.' && !((p[1] == '\0') ||
467 (p[1] == '.' && p[2] == '\0'))) {
468 result |= FILE_ATTRIBUTE_HIDDEN;
469 }
470 }
471
472 result |= dos_mode_from_sbuf(conn, smb_fname);
473
474 /* Optimization : Only call is_hidden_path if it's not already
475 hidden. */
476 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
477 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
478 result |= FILE_ATTRIBUTE_HIDDEN;
479 }
480
481 if (result == 0) {
482 result = FILE_ATTRIBUTE_NORMAL;
483 }
484
485 result = filter_mode_by_protocol(result);
486
487 /*
488 * Add in that it is a reparse point
489 */
490 result |= FILE_ATTRIBUTE_REPARSE_POINT;
491
492 DEBUG(8,("dos_mode_msdfs returning "));
493
494 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
495 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
496 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
497 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
498 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
499 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
500
501 DEBUG(8,("\n"));
502
503 return(result);
504}
505
506#ifdef HAVE_STAT_DOS_FLAGS
507/****************************************************************************
508 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
509****************************************************************************/
510
511int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
512{
513 uint32_t dos_stat_flags = 0;
514
515 if (dosmode & FILE_ATTRIBUTE_ARCHIVE)
516 dos_stat_flags |= UF_DOS_ARCHIVE;
517 if (dosmode & FILE_ATTRIBUTE_HIDDEN)
518 dos_stat_flags |= UF_DOS_HIDDEN;
519 if (dosmode & FILE_ATTRIBUTE_READONLY)
520 dos_stat_flags |= UF_DOS_RO;
521 if (dosmode & FILE_ATTRIBUTE_SYSTEM)
522 dos_stat_flags |= UF_DOS_SYSTEM;
523 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
524 dos_stat_flags |= UF_DOS_NOINDEX;
525
526 return dos_stat_flags;
527}
528
529/****************************************************************************
530 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
531****************************************************************************/
532
533static bool get_stat_dos_flags(connection_struct *conn,
534 const struct smb_filename *smb_fname,
535 uint32_t *dosmode)
536{
537 SMB_ASSERT(VALID_STAT(smb_fname->st));
538 SMB_ASSERT(dosmode);
539
540 if (!lp_store_dos_attributes(SNUM(conn))) {
541 return false;
542 }
543
544 DEBUG(5, ("Getting stat dos attributes for %s.\n",
545 smb_fname_str_dbg(smb_fname)));
546
547 if (smb_fname->st.st_ex_flags & UF_DOS_ARCHIVE)
548 *dosmode |= FILE_ATTRIBUTE_ARCHIVE;
549 if (smb_fname->st.st_ex_flags & UF_DOS_HIDDEN)
550 *dosmode |= FILE_ATTRIBUTE_HIDDEN;
551 if (smb_fname->st.st_ex_flags & UF_DOS_RO)
552 *dosmode |= FILE_ATTRIBUTE_READONLY;
553 if (smb_fname->st.st_ex_flags & UF_DOS_SYSTEM)
554 *dosmode |= FILE_ATTRIBUTE_SYSTEM;
555 if (smb_fname->st.st_ex_flags & UF_DOS_NOINDEX)
556 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
557 if (smb_fname->st.st_ex_flags & FILE_ATTRIBUTE_SPARSE)
558 *dosmode |= FILE_ATTRIBUTE_SPARSE;
559 if (S_ISDIR(smb_fname->st.st_ex_mode))
560 *dosmode |= FILE_ATTRIBUTE_DIRECTORY;
561
562 *dosmode |= set_link_read_only_flag(&smb_fname->st);
563
564 return true;
565}
566
567/****************************************************************************
568 Sets DOS attributes, stored in st_ex_flags of the inode.
569****************************************************************************/
570
571static bool set_stat_dos_flags(connection_struct *conn,
572 const struct smb_filename *smb_fname,
573 uint32_t dosmode,
574 bool *attributes_changed)
575{
576 uint32_t new_flags = 0;
577 int error = 0;
578
579 SMB_ASSERT(VALID_STAT(smb_fname->st));
580 SMB_ASSERT(attributes_changed);
581
582 *attributes_changed = false;
583
584 if (!lp_store_dos_attributes(SNUM(conn))) {
585 return false;
586 }
587
588 DEBUG(5, ("Setting stat dos attributes for %s.\n",
589 smb_fname_str_dbg(smb_fname)));
590
591 new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) |
592 dos_attributes_to_stat_dos_flags(dosmode);
593
594 /* Return early if no flags changed. */
595 if (new_flags == smb_fname->st.st_ex_flags)
596 return true;
597
598 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
599 smb_fname->st.st_ex_flags));
600
601 /* Set new flags with chflags. */
602 error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags);
603 if (error) {
604 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
605 "file %s! errno=%d\n", new_flags,
606 smb_fname_str_dbg(smb_fname), errno));
607 return false;
608 }
609
610 *attributes_changed = true;
611 return true;
612}
613#endif /* HAVE_STAT_DOS_FLAGS */
614
615/****************************************************************************
616 Change a unix mode to a dos mode.
617 May also read the create timespec into the stat struct in smb_fname
618 if "store dos attributes" is true.
619****************************************************************************/
620
621uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
622{
623 uint32 result = 0;
624 bool offline, used_stat_dos_flags = false;
625
626 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
627
628 if (!VALID_STAT(smb_fname->st)) {
629 return 0;
630 }
631
632 /* First do any modifications that depend on the path name. */
633 /* hide files with a name starting with a . */
634 if (lp_hide_dot_files(SNUM(conn))) {
635 const char *p = strrchr_m(smb_fname->base_name,'/');
636 if (p) {
637 p++;
638 } else {
639 p = smb_fname->base_name;
640 }
641
642 /* Only . and .. are not hidden. */
643 if (p[0] == '.' && !((p[1] == '\0') ||
644 (p[1] == '.' && p[2] == '\0'))) {
645 result |= FILE_ATTRIBUTE_HIDDEN;
646 }
647 }
648
649#ifdef HAVE_STAT_DOS_FLAGS
650 used_stat_dos_flags = get_stat_dos_flags(conn, smb_fname, &result);
651#endif
652 if (!used_stat_dos_flags) {
653 /* Get the DOS attributes from an EA by preference. */
654 if (!get_ea_dos_attribute(conn, smb_fname, &result)) {
655 result |= dos_mode_from_sbuf(conn, smb_fname);
656 }
657 }
658
659 offline = SMB_VFS_IS_OFFLINE(conn, smb_fname, &smb_fname->st);
660 if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
661 result |= FILE_ATTRIBUTE_OFFLINE;
662 }
663
664 /* Optimization : Only call is_hidden_path if it's not already
665 hidden. */
666 if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
667 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
668 result |= FILE_ATTRIBUTE_HIDDEN;
669 }
670
671 if (result == 0) {
672 result = FILE_ATTRIBUTE_NORMAL;
673 }
674
675 result = filter_mode_by_protocol(result);
676
677 DEBUG(8,("dos_mode returning "));
678
679 if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h"));
680 if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r"));
681 if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s"));
682 if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d"));
683 if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a"));
684 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
685
686 DEBUG(8,("\n"));
687
688 return(result);
689}
690
691/*******************************************************************
692 chmod a file - but preserve some bits.
693 If "store dos attributes" is also set it will store the create time
694 from the stat struct in smb_fname (in NTTIME format) in the EA
695 attribute also.
696********************************************************************/
697
698int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
699 uint32 dosmode, const char *parent_dir, bool newfile)
700{
701 int mask=0;
702 mode_t tmp;
703 mode_t unixmode;
704 int ret = -1, lret = -1;
705 uint32_t old_mode;
706 struct timespec new_create_timespec;
707
708 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
709 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
710
711 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
712 dosmode, smb_fname_str_dbg(smb_fname)));
713
714 unixmode = smb_fname->st.st_ex_mode;
715
716 get_acl_group_bits(conn, smb_fname->base_name,
717 &smb_fname->st.st_ex_mode);
718
719 if (S_ISDIR(smb_fname->st.st_ex_mode))
720 dosmode |= FILE_ATTRIBUTE_DIRECTORY;
721 else
722 dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
723
724 new_create_timespec = smb_fname->st.st_ex_btime;
725
726 old_mode = dos_mode(conn, smb_fname);
727
728 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
729 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
730 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname);
731 if (lret == -1) {
732 DEBUG(0, ("set_dos_mode: client has asked to "
733 "set FILE_ATTRIBUTE_OFFLINE to "
734 "%s/%s but there was an error while "
735 "setting it or it is not "
736 "supported.\n", parent_dir,
737 smb_fname_str_dbg(smb_fname)));
738 }
739 }
740 }
741
742 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
743 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
744
745 smb_fname->st.st_ex_btime = new_create_timespec;
746
747#ifdef HAVE_STAT_DOS_FLAGS
748 {
749 bool attributes_changed;
750
751 if (set_stat_dos_flags(conn, smb_fname, dosmode,
752 &attributes_changed))
753 {
754 if (!newfile && attributes_changed) {
755 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
756 FILE_NOTIFY_CHANGE_ATTRIBUTES,
757 smb_fname->base_name);
758 }
759 smb_fname->st.st_ex_mode = unixmode;
760 return 0;
761 }
762 }
763#endif
764 /* Store the DOS attributes in an EA by preference. */
765 if (set_ea_dos_attribute(conn, smb_fname, dosmode)) {
766 if (!newfile) {
767 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
768 FILE_NOTIFY_CHANGE_ATTRIBUTES,
769 smb_fname->base_name);
770 }
771 smb_fname->st.st_ex_mode = unixmode;
772 return 0;
773 }
774
775 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
776
777 /* preserve the s bits */
778 mask |= (S_ISUID | S_ISGID);
779
780 /* preserve the t bit */
781#ifdef S_ISVTX
782 mask |= S_ISVTX;
783#endif
784
785 /* possibly preserve the x bits */
786 if (!MAP_ARCHIVE(conn))
787 mask |= S_IXUSR;
788 if (!MAP_SYSTEM(conn))
789 mask |= S_IXGRP;
790 if (!MAP_HIDDEN(conn))
791 mask |= S_IXOTH;
792
793 unixmode |= (smb_fname->st.st_ex_mode & mask);
794
795 /* if we previously had any r bits set then leave them alone */
796 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
797 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
798 unixmode |= tmp;
799 }
800
801 /* if we previously had any w bits set then leave them alone
802 whilst adding in the new w bits, if the new mode is not rdonly */
803 if (!IS_DOS_READONLY(dosmode)) {
804 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
805 }
806
807 /*
808 * From the chmod 2 man page:
809 *
810 * "If the calling process is not privileged, and the group of the file
811 * does not match the effective group ID of the process or one of its
812 * supplementary group IDs, the S_ISGID bit will be turned off, but
813 * this will not cause an error to be returned."
814 *
815 * Simply refuse to do the chmod in this case.
816 */
817
818 if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
819 geteuid() != sec_initial_uid() &&
820 !current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
821 DEBUG(3,("file_set_dosmode: setgid bit cannot be "
822 "set for directory %s\n",
823 smb_fname_str_dbg(smb_fname)));
824 errno = EPERM;
825 return -1;
826 }
827
828 ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
829 if (ret == 0) {
830 if(!newfile || (lret != -1)) {
831 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
832 FILE_NOTIFY_CHANGE_ATTRIBUTES,
833 smb_fname->base_name);
834 }
835 smb_fname->st.st_ex_mode = unixmode;
836 return 0;
837 }
838
839 if((errno != EPERM) && (errno != EACCES))
840 return -1;
841
842 if(!lp_dos_filemode(SNUM(conn)))
843 return -1;
844
845 /* We want DOS semantics, ie allow non owner with write permission to change the
846 bits on a file. Just like file_ntimes below.
847 */
848
849 /* Check if we have write access. */
850 if (CAN_WRITE(conn)) {
851 /*
852 * We need to open the file with write access whilst
853 * still in our current user context. This ensures we
854 * are not violating security in doing the fchmod.
855 */
856 files_struct *fsp;
857 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname,
858 &fsp)))
859 return -1;
860 become_root();
861 ret = SMB_VFS_FCHMOD(fsp, unixmode);
862 unbecome_root();
863 close_file(NULL, fsp, NORMAL_CLOSE);
864 if (!newfile) {
865 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
866 FILE_NOTIFY_CHANGE_ATTRIBUTES,
867 smb_fname->base_name);
868 }
869 if (ret == 0) {
870 smb_fname->st.st_ex_mode = unixmode;
871 }
872 }
873
874 return( ret );
875}
876
877
878NTSTATUS file_set_sparse(connection_struct *conn,
879 files_struct *fsp,
880 bool sparse)
881{
882 uint32_t old_dosmode;
883 uint32_t new_dosmode;
884 NTSTATUS status;
885
886 if (!CAN_WRITE(conn)) {
887 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
888 "on readonly share[%s]\n",
889 smb_fname_str_dbg(fsp->fsp_name),
890 sparse,
891 lp_servicename(SNUM(conn))));
892 return NT_STATUS_MEDIA_WRITE_PROTECTED;
893 }
894
895 if (!(fsp->access_mask & FILE_WRITE_DATA) &&
896 !(fsp->access_mask & FILE_WRITE_ATTRIBUTES)) {
897 DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
898 "access_mask[0x%08X] - access denied\n",
899 smb_fname_str_dbg(fsp->fsp_name),
900 sparse,
901 fsp->access_mask));
902 return NT_STATUS_ACCESS_DENIED;
903 }
904
905 DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
906 sparse, smb_fname_str_dbg(fsp->fsp_name)));
907
908 if (!lp_store_dos_attributes(SNUM(conn))) {
909 return NT_STATUS_INVALID_DEVICE_REQUEST;
910 }
911
912 status = vfs_stat_fsp(fsp);
913 if (!NT_STATUS_IS_OK(status)) {
914 return status;
915 }
916
917 old_dosmode = dos_mode(conn, fsp->fsp_name);
918
919 if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
920 new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
921 } else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
922 new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
923 } else {
924 return NT_STATUS_OK;
925 }
926
927 /* Store the DOS attributes in an EA. */
928 if (!set_ea_dos_attribute(conn, fsp->fsp_name,
929 new_dosmode)) {
930 if (errno == 0) {
931 errno = EIO;
932 }
933 return map_nt_error_from_unix(errno);
934 }
935
936 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
937 FILE_NOTIFY_CHANGE_ATTRIBUTES,
938 fsp->fsp_name->base_name);
939
940 fsp->is_sparse = sparse;
941
942 return NT_STATUS_OK;
943}
944
945/*******************************************************************
946 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
947 than POSIX.
948*******************************************************************/
949
950int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
951 struct smb_file_time *ft)
952{
953 int ret = -1;
954
955 errno = 0;
956
957 DEBUG(6, ("file_ntime: actime: %s",
958 time_to_asc(convert_timespec_to_time_t(ft->atime))));
959 DEBUG(6, ("file_ntime: modtime: %s",
960 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
961 DEBUG(6, ("file_ntime: ctime: %s",
962 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
963 DEBUG(6, ("file_ntime: createtime: %s",
964 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
965
966 /* Don't update the time on read-only shares */
967 /* We need this as set_filetime (which can be called on
968 close and other paths) can end up calling this function
969 without the NEED_WRITE protection. Found by :
970 Leo Weppelman <leo@wau.mis.ah.nl>
971 */
972
973 if (!CAN_WRITE(conn)) {
974 return 0;
975 }
976
977 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
978 return 0;
979 }
980
981 if((errno != EPERM) && (errno != EACCES)) {
982 return -1;
983 }
984
985 if(!lp_dos_filetimes(SNUM(conn))) {
986 return -1;
987 }
988
989 /* We have permission (given by the Samba admin) to
990 break POSIX semantics and allow a user to change
991 the time on a file they don't own but can write to
992 (as DOS does).
993 */
994
995 /* Check if we have write access. */
996 if (can_write_to_file(conn, smb_fname)) {
997 /* We are allowed to become root and change the filetime. */
998 become_root();
999 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1000 unbecome_root();
1001 }
1002
1003 return ret;
1004}
1005
1006/******************************************************************
1007 Force a "sticky" write time on a pathname. This will always be
1008 returned on all future write time queries and set on close.
1009******************************************************************/
1010
1011bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1012{
1013 if (null_timespec(mtime)) {
1014 return true;
1015 }
1016
1017 if (!set_sticky_write_time(fileid, mtime)) {
1018 return false;
1019 }
1020
1021 return true;
1022}
1023
1024/******************************************************************
1025 Force a "sticky" write time on an fsp. This will always be
1026 returned on all future write time queries and set on close.
1027******************************************************************/
1028
1029bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1030{
1031 if (null_timespec(mtime)) {
1032 return true;
1033 }
1034
1035 fsp->write_time_forced = true;
1036 TALLOC_FREE(fsp->update_write_time_event);
1037
1038 return set_sticky_write_time_path(fsp->file_id, mtime);
1039}
1040
1041/******************************************************************
1042 Set a create time EA.
1043******************************************************************/
1044
1045NTSTATUS set_create_timespec_ea(connection_struct *conn,
1046 const struct smb_filename *psmb_fname,
1047 struct timespec create_time)
1048{
1049 NTSTATUS status;
1050 struct smb_filename *smb_fname = NULL;
1051 uint32_t dosmode;
1052 int ret;
1053
1054 if (!lp_store_dos_attributes(SNUM(conn))) {
1055 return NT_STATUS_OK;
1056 }
1057
1058 status = create_synthetic_smb_fname(talloc_tos(),
1059 psmb_fname->base_name,
1060 NULL, &psmb_fname->st,
1061 &smb_fname);
1062
1063 if (!NT_STATUS_IS_OK(status)) {
1064 return status;
1065 }
1066
1067 dosmode = dos_mode(conn, smb_fname);
1068
1069 smb_fname->st.st_ex_btime = create_time;
1070
1071 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1072 if (ret == -1) {
1073 map_nt_error_from_unix(errno);
1074 }
1075
1076 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1077 smb_fname_str_dbg(smb_fname)));
1078
1079 return NT_STATUS_OK;
1080}
1081
1082/******************************************************************
1083 Return a create time.
1084******************************************************************/
1085
1086struct timespec get_create_timespec(connection_struct *conn,
1087 struct files_struct *fsp,
1088 const struct smb_filename *smb_fname)
1089{
1090 return smb_fname->st.st_ex_btime;
1091}
1092
1093/******************************************************************
1094 Return a change time (may look at EA in future).
1095******************************************************************/
1096
1097struct timespec get_change_timespec(connection_struct *conn,
1098 struct files_struct *fsp,
1099 const struct smb_filename *smb_fname)
1100{
1101 return smb_fname->st.st_ex_mtime;
1102}
Note: See TracBrowser for help on using the repository browser.