source: branches/samba-3.5.x/source3/smbd/dosmode.c@ 717

Last change on this file since 717 was 599, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update trunk to 3.5.9

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