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

Last change on this file was 773, checked in by Herwig Bauernfeind, 12 years ago

Samba Server 3.5: Update branch to 3.5.20

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