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

Last change on this file was 597, checked in by Herwig Bauernfeind, 14 years ago

Samba 3.5: Update vendor to version 3.5.9

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