source: trunk/server/source3/smbd/dosmode.c@ 465

Last change on this file since 465 was 454, checked in by Silvan Scherrer, 15 years ago

Samba Server 3.5: merged changes from 3.3

File size: 28.4 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(NULL, 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_fchmod(NULL, fsp);
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 ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
817 if (ret == 0) {
818 if(!newfile || (lret != -1)) {
819 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
820 FILE_NOTIFY_CHANGE_ATTRIBUTES,
821 smb_fname->base_name);
822 }
823 smb_fname->st.st_ex_mode = unixmode;
824 return 0;
825 }
826
827 if((errno != EPERM) && (errno != EACCES))
828 return -1;
829
830 if(!lp_dos_filemode(SNUM(conn)))
831 return -1;
832
833 /* We want DOS semantics, ie allow non owner with write permission to change the
834 bits on a file. Just like file_ntimes below.
835 */
836
837 /* Check if we have write access. */
838 if (CAN_WRITE(conn)) {
839 /*
840 * We need to open the file with write access whilst
841 * still in our current user context. This ensures we
842 * are not violating security in doing the fchmod.
843 * This file open does *not* break any oplocks we are
844 * holding. We need to review this.... may need to
845 * break batch oplocks open by others. JRA.
846 */
847 files_struct *fsp;
848 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
849 &fsp)))
850 return -1;
851 become_root();
852 ret = SMB_VFS_FCHMOD(fsp, unixmode);
853 unbecome_root();
854 close_file_fchmod(NULL, fsp);
855 if (!newfile) {
856 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
857 FILE_NOTIFY_CHANGE_ATTRIBUTES,
858 smb_fname->base_name);
859 }
860 if (ret == 0) {
861 smb_fname->st.st_ex_mode = unixmode;
862 }
863 }
864
865 return( ret );
866}
867
868/*******************************************************************
869 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
870 than POSIX.
871*******************************************************************/
872
873int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
874 struct smb_file_time *ft)
875{
876 int ret = -1;
877
878 errno = 0;
879
880 DEBUG(6, ("file_ntime: actime: %s",
881 time_to_asc(convert_timespec_to_time_t(ft->atime))));
882 DEBUG(6, ("file_ntime: modtime: %s",
883 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
884 DEBUG(6, ("file_ntime: ctime: %s",
885 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
886 DEBUG(6, ("file_ntime: createtime: %s",
887 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
888
889 /* Don't update the time on read-only shares */
890 /* We need this as set_filetime (which can be called on
891 close and other paths) can end up calling this function
892 without the NEED_WRITE protection. Found by :
893 Leo Weppelman <leo@wau.mis.ah.nl>
894 */
895
896 if (!CAN_WRITE(conn)) {
897 return 0;
898 }
899
900 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
901 return 0;
902 }
903
904 if((errno != EPERM) && (errno != EACCES)) {
905 return -1;
906 }
907
908 if(!lp_dos_filetimes(SNUM(conn))) {
909 return -1;
910 }
911
912 /* We have permission (given by the Samba admin) to
913 break POSIX semantics and allow a user to change
914 the time on a file they don't own but can write to
915 (as DOS does).
916 */
917
918 /* Check if we have write access. */
919 if (can_write_to_file(conn, smb_fname)) {
920 /* We are allowed to become root and change the filetime. */
921 become_root();
922 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
923 unbecome_root();
924 }
925
926 return ret;
927}
928
929/******************************************************************
930 Force a "sticky" write time on a pathname. This will always be
931 returned on all future write time queries and set on close.
932******************************************************************/
933
934bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
935{
936 if (null_timespec(mtime)) {
937 return true;
938 }
939
940 if (!set_sticky_write_time(fileid, mtime)) {
941 return false;
942 }
943
944 return true;
945}
946
947/******************************************************************
948 Force a "sticky" write time on an fsp. This will always be
949 returned on all future write time queries and set on close.
950******************************************************************/
951
952bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
953{
954 if (null_timespec(mtime)) {
955 return true;
956 }
957
958 fsp->write_time_forced = true;
959 TALLOC_FREE(fsp->update_write_time_event);
960
961 return set_sticky_write_time_path(fsp->file_id, mtime);
962}
963
964/******************************************************************
965 Set a create time EA.
966******************************************************************/
967
968NTSTATUS set_create_timespec_ea(connection_struct *conn,
969 const struct smb_filename *psmb_fname,
970 struct timespec create_time)
971{
972 NTSTATUS status;
973 struct smb_filename *smb_fname = NULL;
974 uint32_t dosmode;
975 int ret;
976
977 if (!lp_store_dos_attributes(SNUM(conn))) {
978 return NT_STATUS_OK;
979 }
980
981 status = create_synthetic_smb_fname(talloc_tos(),
982 psmb_fname->base_name,
983 NULL, &psmb_fname->st,
984 &smb_fname);
985
986 if (!NT_STATUS_IS_OK(status)) {
987 return status;
988 }
989
990 dosmode = dos_mode(conn, smb_fname);
991
992 smb_fname->st.st_ex_btime = create_time;
993
994 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
995 if (ret == -1) {
996 map_nt_error_from_unix(errno);
997 }
998
999 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1000 smb_fname_str_dbg(smb_fname)));
1001
1002 return NT_STATUS_OK;
1003}
1004
1005/******************************************************************
1006 Return a create time.
1007******************************************************************/
1008
1009struct timespec get_create_timespec(connection_struct *conn,
1010 struct files_struct *fsp,
1011 const struct smb_filename *smb_fname)
1012{
1013 return smb_fname->st.st_ex_btime;
1014}
1015
1016/******************************************************************
1017 Return a change time (may look at EA in future).
1018******************************************************************/
1019
1020struct timespec get_change_timespec(connection_struct *conn,
1021 struct files_struct *fsp,
1022 const struct smb_filename *smb_fname)
1023{
1024 return smb_fname->st.st_ex_mtime;
1025}
Note: See TracBrowser for help on using the repository browser.