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

Last change on this file since 429 was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 27.8 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 if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
183 result |= aRONLY;
184 }
185 } else if (ro_opts == MAP_READONLY_PERMISSIONS) {
186 /* Check actual permissions for read-only. */
187 if (!can_write_to_file(conn, smb_fname)) {
188 result |= aRONLY;
189 }
190 } /* Else never set the readonly bit. */
191
192 if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
193 result |= aARCH;
194
195 if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
196 result |= aSYSTEM;
197
198 if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
199 result |= aHIDDEN;
200
201 if (S_ISDIR(smb_fname->st.st_ex_mode))
202 result = aDIR | (result & aRONLY);
203
204 result |= set_sparse_flag(&smb_fname->st);
205 result |= set_link_read_only_flag(&smb_fname->st);
206
207 DEBUG(8,("dos_mode_from_sbuf returning "));
208
209 if (result & aHIDDEN) DEBUG(8, ("h"));
210 if (result & aRONLY ) DEBUG(8, ("r"));
211 if (result & aSYSTEM) DEBUG(8, ("s"));
212 if (result & aDIR ) DEBUG(8, ("d"));
213 if (result & aARCH ) DEBUG(8, ("a"));
214
215 DEBUG(8,("\n"));
216 return result;
217}
218
219/****************************************************************************
220 Get DOS attributes from an EA.
221 This can also pull the create time into the stat struct inside smb_fname.
222****************************************************************************/
223
224static bool get_ea_dos_attribute(connection_struct *conn,
225 struct smb_filename *smb_fname,
226 uint32 *pattr)
227{
228 struct xattr_DOSATTRIB dosattrib;
229 enum ndr_err_code ndr_err;
230 DATA_BLOB blob;
231 ssize_t sizeret;
232 fstring attrstr;
233 uint32_t dosattr;
234
235 if (!lp_store_dos_attributes(SNUM(conn))) {
236 return False;
237 }
238
239 /* Don't reset pattr to zero as we may already have filename-based attributes we
240 need to preserve. */
241
242 sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name,
243 SAMBA_XATTR_DOS_ATTRIB, attrstr,
244 sizeof(attrstr));
245 if (sizeret == -1) {
246 if (errno == ENOSYS
247#if defined(ENOTSUP)
248 || errno == ENOTSUP) {
249#else
250 ) {
251#endif
252 DEBUG(1,("get_ea_dos_attributes: Cannot get attribute "
253 "from EA on file %s: Error = %s\n",
254 smb_fname_str_dbg(smb_fname),
255 strerror(errno)));
256 set_store_dos_attributes(SNUM(conn), False);
257 }
258 return False;
259 }
260
261 blob.data = (uint8_t *)attrstr;
262 blob.length = sizeret;
263
264 ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), NULL, &dosattrib,
265 (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
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_attributes: 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_attributes: 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_attributes: 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 |= aDIR;
322 }
323 *pattr = (uint32)(dosattr & SAMBA_ATTRIBUTES_MASK);
324
325 DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr));
326
327 if (dosattr & aHIDDEN) DEBUG(8, ("h"));
328 if (dosattr & aRONLY ) DEBUG(8, ("r"));
329 if (dosattr & aSYSTEM) DEBUG(8, ("s"));
330 if (dosattr & aDIR ) DEBUG(8, ("d"));
331 if (dosattr & aARCH ) DEBUG(8, ("a"));
332
333 DEBUG(8,("\n"));
334
335 return True;
336}
337
338/****************************************************************************
339 Set DOS attributes in an EA.
340 Also sets the create time.
341****************************************************************************/
342
343static bool set_ea_dos_attribute(connection_struct *conn,
344 struct smb_filename *smb_fname,
345 uint32 dosmode)
346{
347 struct xattr_DOSATTRIB dosattrib;
348 enum ndr_err_code ndr_err;
349 DATA_BLOB blob;
350 files_struct *fsp = NULL;
351 bool ret = false;
352
353 if (!lp_store_dos_attributes(SNUM(conn))) {
354 return False;
355 }
356
357 ZERO_STRUCT(dosattrib);
358 ZERO_STRUCT(blob);
359
360 dosattrib.version = 3;
361 dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB|
362 XATTR_DOSINFO_CREATE_TIME;
363 dosattrib.info.info3.attrib = dosmode;
364 unix_timespec_to_nt_time(&dosattrib.info.info3.create_time,
365 smb_fname->st.st_ex_btime);
366
367 ndr_err = ndr_push_struct_blob(
368 &blob, talloc_tos(), NULL, &dosattrib,
369 (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
370
371 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
372 DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
373 ndr_errstr(ndr_err)));
374 return false;
375 }
376
377 if (blob.data == NULL || blob.length == 0) {
378 return false;
379 }
380
381 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
382 SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
383 0) == -1) {
384 if((errno != EPERM) && (errno != EACCES)) {
385 if (errno == ENOSYS
386#if defined(ENOTSUP)
387 || errno == ENOTSUP) {
388#else
389 ) {
390#endif
391 DEBUG(1,("set_ea_dos_attributes: Cannot set "
392 "attribute EA on file %s: Error = %s\n",
393 smb_fname_str_dbg(smb_fname),
394 strerror(errno) ));
395 set_store_dos_attributes(SNUM(conn), False);
396 }
397 return false;
398 }
399
400 /* We want DOS semantics, ie allow non owner with write permission to change the
401 bits on a file. Just like file_ntimes below.
402 */
403
404 /* Check if we have write access. */
405 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
406 return false;
407
408 /*
409 * We need to open the file with write access whilst
410 * still in our current user context. This ensures we
411 * are not violating security in doing the setxattr.
412 */
413
414 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
415 &fsp)))
416 return ret;
417 become_root();
418 if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
419 SAMBA_XATTR_DOS_ATTRIB, blob.data,
420 blob.length, 0) == 0) {
421 ret = true;
422 }
423 unbecome_root();
424 close_file_fchmod(NULL, fsp);
425 return ret;
426 }
427 DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
428 (unsigned int)dosmode,
429 smb_fname_str_dbg(smb_fname)));
430 return true;
431}
432
433/****************************************************************************
434 Change a unix mode to a dos mode for an ms dfs link.
435****************************************************************************/
436
437uint32 dos_mode_msdfs(connection_struct *conn,
438 const struct smb_filename *smb_fname)
439{
440 uint32 result = 0;
441
442 DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
443
444 if (!VALID_STAT(smb_fname->st)) {
445 return 0;
446 }
447
448 /* First do any modifications that depend on the path name. */
449 /* hide files with a name starting with a . */
450 if (lp_hide_dot_files(SNUM(conn))) {
451 const char *p = strrchr_m(smb_fname->base_name, '/');
452 if (p) {
453 p++;
454 } else {
455 p = smb_fname->base_name;
456 }
457
458 /* Only . and .. are not hidden. */
459 if (p[0] == '.' && !((p[1] == '\0') ||
460 (p[1] == '.' && p[2] == '\0'))) {
461 result |= aHIDDEN;
462 }
463 }
464
465 result |= dos_mode_from_sbuf(conn, smb_fname);
466
467 /* Optimization : Only call is_hidden_path if it's not already
468 hidden. */
469 if (!(result & aHIDDEN) &&
470 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
471 result |= aHIDDEN;
472 }
473
474 if (result == 0) {
475 result = FILE_ATTRIBUTE_NORMAL;
476 }
477
478 result = filter_mode_by_protocol(result);
479
480 DEBUG(8,("dos_mode_msdfs returning "));
481
482 if (result & aHIDDEN) DEBUG(8, ("h"));
483 if (result & aRONLY ) DEBUG(8, ("r"));
484 if (result & aSYSTEM) DEBUG(8, ("s"));
485 if (result & aDIR ) DEBUG(8, ("d"));
486 if (result & aARCH ) DEBUG(8, ("a"));
487 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
488
489 DEBUG(8,("\n"));
490
491 return(result);
492}
493
494#ifdef HAVE_STAT_DOS_FLAGS
495/****************************************************************************
496 Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
497****************************************************************************/
498
499int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
500{
501 uint32_t dos_stat_flags = 0;
502
503 if (dosmode & aARCH)
504 dos_stat_flags |= UF_DOS_ARCHIVE;
505 if (dosmode & aHIDDEN)
506 dos_stat_flags |= UF_DOS_HIDDEN;
507 if (dosmode & aRONLY)
508 dos_stat_flags |= UF_DOS_RO;
509 if (dosmode & aSYSTEM)
510 dos_stat_flags |= UF_DOS_SYSTEM;
511 if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
512 dos_stat_flags |= UF_DOS_NOINDEX;
513
514 return dos_stat_flags;
515}
516
517/****************************************************************************
518 Gets DOS attributes, accessed via st_ex_flags in the stat struct.
519****************************************************************************/
520
521static bool get_stat_dos_flags(connection_struct *conn,
522 const struct smb_filename *smb_fname,
523 uint32_t *dosmode)
524{
525 SMB_ASSERT(VALID_STAT(smb_fname->st));
526 SMB_ASSERT(dosmode);
527
528 if (!lp_store_dos_attributes(SNUM(conn))) {
529 return false;
530 }
531
532 DEBUG(5, ("Getting stat dos attributes for %s.\n",
533 smb_fname_str_dbg(smb_fname)));
534
535 if (smb_fname->st.st_ex_flags & UF_DOS_ARCHIVE)
536 *dosmode |= aARCH;
537 if (smb_fname->st.st_ex_flags & UF_DOS_HIDDEN)
538 *dosmode |= aHIDDEN;
539 if (smb_fname->st.st_ex_flags & UF_DOS_RO)
540 *dosmode |= aRONLY;
541 if (smb_fname->st.st_ex_flags & UF_DOS_SYSTEM)
542 *dosmode |= aSYSTEM;
543 if (smb_fname->st.st_ex_flags & UF_DOS_NOINDEX)
544 *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
545 if (S_ISDIR(smb_fname->st.st_ex_mode))
546 *dosmode |= aDIR;
547
548 *dosmode |= set_sparse_flag(&smb_fname->st);
549 *dosmode |= set_link_read_only_flag(&smb_fname->st);
550
551 return true;
552}
553
554/****************************************************************************
555 Sets DOS attributes, stored in st_ex_flags of the inode.
556****************************************************************************/
557
558static bool set_stat_dos_flags(connection_struct *conn,
559 const struct smb_filename *smb_fname,
560 uint32_t dosmode,
561 bool *attributes_changed)
562{
563 uint32_t new_flags = 0;
564 int error = 0;
565
566 SMB_ASSERT(VALID_STAT(smb_fname->st));
567 SMB_ASSERT(attributes_changed);
568
569 *attributes_changed = false;
570
571 if (!lp_store_dos_attributes(SNUM(conn))) {
572 return false;
573 }
574
575 DEBUG(5, ("Setting stat dos attributes for %s.\n",
576 smb_fname_str_dbg(smb_fname)));
577
578 new_flags = (smb_fname->st.st_ex_flags & ~UF_DOS_FLAGS) |
579 dos_attributes_to_stat_dos_flags(dosmode);
580
581 /* Return early if no flags changed. */
582 if (new_flags == smb_fname->st.st_ex_flags)
583 return true;
584
585 DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
586 smb_fname->st.st_ex_flags));
587
588 /* Set new flags with chflags. */
589 error = SMB_VFS_CHFLAGS(conn, smb_fname->base_name, new_flags);
590 if (error) {
591 DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
592 "file %s! errno=%d\n", new_flags,
593 smb_fname_str_dbg(smb_fname), errno));
594 return false;
595 }
596
597 *attributes_changed = true;
598 return true;
599}
600#endif /* HAVE_STAT_DOS_FLAGS */
601
602/****************************************************************************
603 Change a unix mode to a dos mode.
604 May also read the create timespec into the stat struct in smb_fname
605 if "store dos attributes" is true.
606****************************************************************************/
607
608uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
609{
610 uint32 result = 0;
611 bool offline, used_stat_dos_flags = false;
612
613 DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
614
615 if (!VALID_STAT(smb_fname->st)) {
616 return 0;
617 }
618
619 /* First do any modifications that depend on the path name. */
620 /* hide files with a name starting with a . */
621 if (lp_hide_dot_files(SNUM(conn))) {
622 const char *p = strrchr_m(smb_fname->base_name,'/');
623 if (p) {
624 p++;
625 } else {
626 p = smb_fname->base_name;
627 }
628
629 /* Only . and .. are not hidden. */
630 if (p[0] == '.' && !((p[1] == '\0') ||
631 (p[1] == '.' && p[2] == '\0'))) {
632 result |= aHIDDEN;
633 }
634 }
635
636#ifdef HAVE_STAT_DOS_FLAGS
637 used_stat_dos_flags = get_stat_dos_flags(conn, smb_fname, &result);
638#endif
639 if (!used_stat_dos_flags) {
640 /* Get the DOS attributes from an EA by preference. */
641 if (get_ea_dos_attribute(conn, smb_fname, &result)) {
642 result |= set_sparse_flag(&smb_fname->st);
643 } else {
644 result |= dos_mode_from_sbuf(conn, smb_fname);
645 }
646 }
647
648 offline = SMB_VFS_IS_OFFLINE(conn, smb_fname->base_name, &smb_fname->st);
649 if (S_ISREG(smb_fname->st.st_ex_mode) && offline) {
650 result |= FILE_ATTRIBUTE_OFFLINE;
651 }
652
653 /* Optimization : Only call is_hidden_path if it's not already
654 hidden. */
655 if (!(result & aHIDDEN) &&
656 IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
657 result |= aHIDDEN;
658 }
659
660 if (result == 0) {
661 result = FILE_ATTRIBUTE_NORMAL;
662 }
663
664 result = filter_mode_by_protocol(result);
665
666 DEBUG(8,("dos_mode returning "));
667
668 if (result & aHIDDEN) DEBUG(8, ("h"));
669 if (result & aRONLY ) DEBUG(8, ("r"));
670 if (result & aSYSTEM) DEBUG(8, ("s"));
671 if (result & aDIR ) DEBUG(8, ("d"));
672 if (result & aARCH ) DEBUG(8, ("a"));
673 if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]"));
674
675 DEBUG(8,("\n"));
676
677 return(result);
678}
679
680/*******************************************************************
681 chmod a file - but preserve some bits.
682 If "store dos attributes" is also set it will store the create time
683 from the stat struct in smb_fname (in NTTIME format) in the EA
684 attribute also.
685********************************************************************/
686
687int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
688 uint32 dosmode, const char *parent_dir, bool newfile)
689{
690 int mask=0;
691 mode_t tmp;
692 mode_t unixmode;
693 int ret = -1, lret = -1;
694 uint32_t old_mode;
695 struct timespec new_create_timespec;
696
697 /* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
698 dosmode &= (SAMBA_ATTRIBUTES_MASK | FILE_ATTRIBUTE_OFFLINE);
699
700 DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
701 dosmode, smb_fname_str_dbg(smb_fname)));
702
703 unixmode = smb_fname->st.st_ex_mode;
704
705 get_acl_group_bits(conn, smb_fname->base_name,
706 &smb_fname->st.st_ex_mode);
707
708 if (S_ISDIR(smb_fname->st.st_ex_mode))
709 dosmode |= aDIR;
710 else
711 dosmode &= ~aDIR;
712
713 new_create_timespec = smb_fname->st.st_ex_btime;
714
715 old_mode = dos_mode(conn, smb_fname);
716
717 if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
718 if (!(old_mode & FILE_ATTRIBUTE_OFFLINE)) {
719 lret = SMB_VFS_SET_OFFLINE(conn, smb_fname->base_name);
720 if (lret == -1) {
721 DEBUG(0, ("set_dos_mode: client has asked to "
722 "set FILE_ATTRIBUTE_OFFLINE to "
723 "%s/%s but there was an error while "
724 "setting it or it is not "
725 "supported.\n", parent_dir,
726 smb_fname_str_dbg(smb_fname)));
727 }
728 }
729 }
730
731 dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
732 old_mode &= ~FILE_ATTRIBUTE_OFFLINE;
733
734 smb_fname->st.st_ex_btime = new_create_timespec;
735
736#ifdef HAVE_STAT_DOS_FLAGS
737 {
738 bool attributes_changed;
739
740 if (set_stat_dos_flags(conn, smb_fname, dosmode,
741 &attributes_changed))
742 {
743 if (!newfile && attributes_changed) {
744 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
745 FILE_NOTIFY_CHANGE_ATTRIBUTES,
746 smb_fname->base_name);
747 }
748 smb_fname->st.st_ex_mode = unixmode;
749 return 0;
750 }
751 }
752#endif
753 /* Store the DOS attributes in an EA by preference. */
754 if (set_ea_dos_attribute(conn, smb_fname, dosmode)) {
755 if (!newfile) {
756 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
757 FILE_NOTIFY_CHANGE_ATTRIBUTES,
758 smb_fname->base_name);
759 }
760 smb_fname->st.st_ex_mode = unixmode;
761 return 0;
762 }
763
764 unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
765
766 /* preserve the s bits */
767 mask |= (S_ISUID | S_ISGID);
768
769 /* preserve the t bit */
770#ifdef S_ISVTX
771 mask |= S_ISVTX;
772#endif
773
774 /* possibly preserve the x bits */
775 if (!MAP_ARCHIVE(conn))
776 mask |= S_IXUSR;
777 if (!MAP_SYSTEM(conn))
778 mask |= S_IXGRP;
779 if (!MAP_HIDDEN(conn))
780 mask |= S_IXOTH;
781
782 unixmode |= (smb_fname->st.st_ex_mode & mask);
783
784 /* if we previously had any r bits set then leave them alone */
785 if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
786 unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
787 unixmode |= tmp;
788 }
789
790 /* if we previously had any w bits set then leave them alone
791 whilst adding in the new w bits, if the new mode is not rdonly */
792 if (!IS_DOS_READONLY(dosmode)) {
793 unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
794 }
795
796 ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
797 if (ret == 0) {
798 if(!newfile || (lret != -1)) {
799 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
800 FILE_NOTIFY_CHANGE_ATTRIBUTES,
801 smb_fname->base_name);
802 }
803 smb_fname->st.st_ex_mode = unixmode;
804 return 0;
805 }
806
807 if((errno != EPERM) && (errno != EACCES))
808 return -1;
809
810 if(!lp_dos_filemode(SNUM(conn)))
811 return -1;
812
813 /* We want DOS semantics, ie allow non owner with write permission to change the
814 bits on a file. Just like file_ntimes below.
815 */
816
817 /* Check if we have write access. */
818 if (CAN_WRITE(conn)) {
819 /*
820 * We need to open the file with write access whilst
821 * still in our current user context. This ensures we
822 * are not violating security in doing the fchmod.
823 * This file open does *not* break any oplocks we are
824 * holding. We need to review this.... may need to
825 * break batch oplocks open by others. JRA.
826 */
827 files_struct *fsp;
828 if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname,
829 &fsp)))
830 return -1;
831 become_root();
832 ret = SMB_VFS_FCHMOD(fsp, unixmode);
833 unbecome_root();
834 close_file_fchmod(NULL, fsp);
835 if (!newfile) {
836 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
837 FILE_NOTIFY_CHANGE_ATTRIBUTES,
838 smb_fname->base_name);
839 }
840 if (ret == 0) {
841 smb_fname->st.st_ex_mode = unixmode;
842 }
843 }
844
845 return( ret );
846}
847
848/*******************************************************************
849 Wrapper around the VFS ntimes that possibly allows DOS semantics rather
850 than POSIX.
851*******************************************************************/
852
853int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
854 struct smb_file_time *ft)
855{
856 int ret = -1;
857
858 errno = 0;
859
860 DEBUG(6, ("file_ntime: actime: %s",
861 time_to_asc(convert_timespec_to_time_t(ft->atime))));
862 DEBUG(6, ("file_ntime: modtime: %s",
863 time_to_asc(convert_timespec_to_time_t(ft->mtime))));
864 DEBUG(6, ("file_ntime: ctime: %s",
865 time_to_asc(convert_timespec_to_time_t(ft->ctime))));
866 DEBUG(6, ("file_ntime: createtime: %s",
867 time_to_asc(convert_timespec_to_time_t(ft->create_time))));
868
869 /* Don't update the time on read-only shares */
870 /* We need this as set_filetime (which can be called on
871 close and other paths) can end up calling this function
872 without the NEED_WRITE protection. Found by :
873 Leo Weppelman <leo@wau.mis.ah.nl>
874 */
875
876 if (!CAN_WRITE(conn)) {
877 return 0;
878 }
879
880 if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
881 return 0;
882 }
883
884 if((errno != EPERM) && (errno != EACCES)) {
885 return -1;
886 }
887
888 if(!lp_dos_filetimes(SNUM(conn))) {
889 return -1;
890 }
891
892 /* We have permission (given by the Samba admin) to
893 break POSIX semantics and allow a user to change
894 the time on a file they don't own but can write to
895 (as DOS does).
896 */
897
898 /* Check if we have write access. */
899 if (can_write_to_file(conn, smb_fname)) {
900 /* We are allowed to become root and change the filetime. */
901 become_root();
902 ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
903 unbecome_root();
904 }
905
906 return ret;
907}
908
909/******************************************************************
910 Force a "sticky" write time on a pathname. This will always be
911 returned on all future write time queries and set on close.
912******************************************************************/
913
914bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
915{
916 if (null_timespec(mtime)) {
917 return true;
918 }
919
920 if (!set_sticky_write_time(fileid, mtime)) {
921 return false;
922 }
923
924 return true;
925}
926
927/******************************************************************
928 Force a "sticky" write time on an fsp. This will always be
929 returned on all future write time queries and set on close.
930******************************************************************/
931
932bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
933{
934 if (null_timespec(mtime)) {
935 return true;
936 }
937
938 fsp->write_time_forced = true;
939 TALLOC_FREE(fsp->update_write_time_event);
940
941 return set_sticky_write_time_path(fsp->file_id, mtime);
942}
943
944/******************************************************************
945 Set a create time EA.
946******************************************************************/
947
948NTSTATUS set_create_timespec_ea(connection_struct *conn,
949 const struct smb_filename *psmb_fname,
950 struct timespec create_time)
951{
952 NTSTATUS status;
953 struct smb_filename *smb_fname = NULL;
954 uint32_t dosmode;
955 int ret;
956
957 if (!lp_store_dos_attributes(SNUM(conn))) {
958 return NT_STATUS_OK;
959 }
960
961 status = create_synthetic_smb_fname(talloc_tos(),
962 psmb_fname->base_name,
963 NULL, &psmb_fname->st,
964 &smb_fname);
965
966 if (!NT_STATUS_IS_OK(status)) {
967 return status;
968 }
969
970 dosmode = dos_mode(conn, smb_fname);
971
972 smb_fname->st.st_ex_btime = create_time;
973
974 ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
975 if (ret == -1) {
976 map_nt_error_from_unix(errno);
977 }
978
979 DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
980 smb_fname_str_dbg(smb_fname)));
981
982 return NT_STATUS_OK;
983}
984
985/******************************************************************
986 Return a create time.
987******************************************************************/
988
989struct timespec get_create_timespec(connection_struct *conn,
990 struct files_struct *fsp,
991 const struct smb_filename *smb_fname)
992{
993 return smb_fname->st.st_ex_btime;
994}
995
996/******************************************************************
997 Return a change time (may look at EA in future).
998******************************************************************/
999
1000struct timespec get_change_timespec(connection_struct *conn,
1001 struct files_struct *fsp,
1002 const struct smb_filename *smb_fname)
1003{
1004 return smb_fname->st.st_ex_mtime;
1005}
Note: See TracBrowser for help on using the repository browser.