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 "globals.h"
23 #include "system/filesys.h"
24 #include "librpc/gen_ndr/ndr_xattr.h"
25 #include "librpc/gen_ndr/ioctl.h"
26 #include "../libcli/security/security.h"
27 #include "smbd/smbd.h"
28 #include "lib/param/loadparm.h"
29 #include "lib/util/tevent_ntstatus.h"
30 
31 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
32 				const struct smb_filename *smb_fname,
33 				files_struct **ret_fsp,
34 				bool *need_close);
35 
dos_mode_debug_print(const char * func,uint32_t mode)36 static void dos_mode_debug_print(const char *func, uint32_t mode)
37 {
38 	fstring modestr;
39 
40 	if (DEBUGLEVEL < DBGLVL_INFO) {
41 		return;
42 	}
43 
44 	modestr[0] = '\0';
45 
46 	if (mode & FILE_ATTRIBUTE_HIDDEN) {
47 		fstrcat(modestr, "h");
48 	}
49 	if (mode & FILE_ATTRIBUTE_READONLY) {
50 		fstrcat(modestr, "r");
51 	}
52 	if (mode & FILE_ATTRIBUTE_SYSTEM) {
53 		fstrcat(modestr, "s");
54 	}
55 	if (mode & FILE_ATTRIBUTE_DIRECTORY) {
56 		fstrcat(modestr, "d");
57 	}
58 	if (mode & FILE_ATTRIBUTE_ARCHIVE) {
59 		fstrcat(modestr, "a");
60 	}
61 	if (mode & FILE_ATTRIBUTE_SPARSE) {
62 		fstrcat(modestr, "[sparse]");
63 	}
64 	if (mode & FILE_ATTRIBUTE_OFFLINE) {
65 		fstrcat(modestr, "[offline]");
66 	}
67 	if (mode & FILE_ATTRIBUTE_COMPRESSED) {
68 		fstrcat(modestr, "[compressed]");
69 	}
70 
71 	DBG_INFO("%s returning (0x%x): \"%s\"\n", func, (unsigned)mode,
72 		 modestr);
73 }
74 
filter_mode_by_protocol(uint32_t mode)75 static uint32_t filter_mode_by_protocol(uint32_t mode)
76 {
77 	if (get_Protocol() <= PROTOCOL_LANMAN2) {
78 		DEBUG(10,("filter_mode_by_protocol: "
79 			"filtering result 0x%x to 0x%x\n",
80 			(unsigned int)mode,
81 			(unsigned int)(mode & 0x3f) ));
82 		mode &= 0x3f;
83 	}
84 	return mode;
85 }
86 
set_link_read_only_flag(const SMB_STRUCT_STAT * const sbuf)87 static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
88 {
89 #ifdef S_ISLNK
90 #if LINKS_READ_ONLY
91 	if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
92 		return FILE_ATTRIBUTE_READONLY;
93 #endif
94 #endif
95 	return 0;
96 }
97 
98 /****************************************************************************
99  Change a dos mode to a unix mode.
100     Base permission for files:
101          if creating file and inheriting (i.e. parent_dir != NULL)
102            apply read/write bits from parent directory.
103          else
104            everybody gets read bit set
105          dos readonly is represented in unix by removing everyone's write bit
106          dos archive is represented in unix by the user's execute bit
107          dos system is represented in unix by the group's execute bit
108          dos hidden is represented in unix by the other's execute bit
109          if !inheriting {
110            Then apply create mask,
111            then add force bits.
112          }
113     Base permission for directories:
114          dos directory is represented in unix by unix's dir bit and the exec bit
115          if !inheriting {
116            Then apply create mask,
117            then add force bits.
118          }
119 ****************************************************************************/
120 
unix_mode(connection_struct * conn,int dosmode,const struct smb_filename * smb_fname,const char * inherit_from_dir)121 mode_t unix_mode(connection_struct *conn, int dosmode,
122 		 const struct smb_filename *smb_fname,
123 		 const char *inherit_from_dir)
124 {
125 	mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
126 	mode_t dir_mode = 0; /* Mode of the inherit_from directory if
127 			      * inheriting. */
128 
129 	if (!lp_store_dos_attributes(SNUM(conn)) && IS_DOS_READONLY(dosmode)) {
130 		result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
131 	}
132 
133 	if ((inherit_from_dir != NULL) && lp_inherit_permissions(SNUM(conn))) {
134 		struct smb_filename *smb_fname_parent;
135 
136 		DEBUG(2, ("unix_mode(%s) inheriting from %s\n",
137 			  smb_fname_str_dbg(smb_fname),
138 			  inherit_from_dir));
139 
140 		smb_fname_parent = synthetic_smb_fname(talloc_tos(),
141 					inherit_from_dir,
142 					NULL,
143 					NULL,
144 					smb_fname->flags);
145 		if (smb_fname_parent == NULL) {
146 			DEBUG(1,("unix_mode(%s) failed, [dir %s]: No memory\n",
147 				 smb_fname_str_dbg(smb_fname),
148 				 inherit_from_dir));
149 			return(0);
150 		}
151 
152 		if (SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
153 			DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",
154 				 smb_fname_str_dbg(smb_fname),
155 				 inherit_from_dir, strerror(errno)));
156 			TALLOC_FREE(smb_fname_parent);
157 			return(0);      /* *** shouldn't happen! *** */
158 		}
159 
160 		/* Save for later - but explicitly remove setuid bit for safety. */
161 		dir_mode = smb_fname_parent->st.st_ex_mode & ~S_ISUID;
162 		DEBUG(2,("unix_mode(%s) inherit mode %o\n",
163 			 smb_fname_str_dbg(smb_fname), (int)dir_mode));
164 		/* Clear "result" */
165 		result = 0;
166 		TALLOC_FREE(smb_fname_parent);
167 	}
168 
169 	if (IS_DOS_DIR(dosmode)) {
170 		/* We never make directories read only for the owner as under DOS a user
171 		can always create a file in a read-only directory. */
172 		result |= (S_IFDIR | S_IWUSR);
173 
174 		if (dir_mode) {
175 			/* Inherit mode of parent directory. */
176 			result |= dir_mode;
177 		} else {
178 			/* Provisionally add all 'x' bits */
179 			result |= (S_IXUSR | S_IXGRP | S_IXOTH);
180 
181 			/* Apply directory mask */
182 			result &= lp_directory_mask(SNUM(conn));
183 			/* Add in force bits */
184 			result |= lp_force_directory_mode(SNUM(conn));
185 		}
186 	} else {
187 		if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode))
188 			result |= S_IXUSR;
189 
190 		if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode))
191 			result |= S_IXGRP;
192 
193 		if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode))
194 			result |= S_IXOTH;
195 
196 		if (dir_mode) {
197 			/* Inherit 666 component of parent directory mode */
198 			result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
199 		} else {
200 			/* Apply mode mask */
201 			result &= lp_create_mask(SNUM(conn));
202 			/* Add in force bits */
203 			result |= lp_force_create_mode(SNUM(conn));
204 		}
205 	}
206 
207 	DBG_INFO("unix_mode(%s) returning 0%o\n",
208 		 smb_fname_str_dbg(smb_fname), (int)result);
209 
210 	return(result);
211 }
212 
213 /****************************************************************************
214  Change a unix mode to a dos mode.
215 ****************************************************************************/
216 
dos_mode_from_sbuf(connection_struct * conn,const struct smb_filename * smb_fname)217 static uint32_t dos_mode_from_sbuf(connection_struct *conn,
218 				 const struct smb_filename *smb_fname)
219 {
220 	int result = 0;
221 	enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn));
222 
223 #if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE)
224 	/* if we can find out if a file is immutable we should report it r/o */
225 	if (smb_fname->st.st_ex_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) {
226 		result |= FILE_ATTRIBUTE_READONLY;
227 	}
228 #endif
229 	if (ro_opts == MAP_READONLY_YES) {
230 		/* Original Samba method - map inverse of user "w" bit. */
231 		if ((smb_fname->st.st_ex_mode & S_IWUSR) == 0) {
232 			result |= FILE_ATTRIBUTE_READONLY;
233 		}
234 	} else if (ro_opts == MAP_READONLY_PERMISSIONS) {
235 		/* Check actual permissions for read-only. */
236 		if (!can_write_to_file(conn, smb_fname)) {
237 			result |= FILE_ATTRIBUTE_READONLY;
238 		}
239 	} /* Else never set the readonly bit. */
240 
241 	if (MAP_ARCHIVE(conn) && ((smb_fname->st.st_ex_mode & S_IXUSR) != 0))
242 		result |= FILE_ATTRIBUTE_ARCHIVE;
243 
244 	if (MAP_SYSTEM(conn) && ((smb_fname->st.st_ex_mode & S_IXGRP) != 0))
245 		result |= FILE_ATTRIBUTE_SYSTEM;
246 
247 	if (MAP_HIDDEN(conn) && ((smb_fname->st.st_ex_mode & S_IXOTH) != 0))
248 		result |= FILE_ATTRIBUTE_HIDDEN;
249 
250 	if (S_ISDIR(smb_fname->st.st_ex_mode))
251 		result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
252 
253 	result |= set_link_read_only_flag(&smb_fname->st);
254 
255 	dos_mode_debug_print(__func__, result);
256 
257 	return result;
258 }
259 
260 /****************************************************************************
261  Get DOS attributes from an EA.
262  This can also pull the create time into the stat struct inside smb_fname.
263 ****************************************************************************/
264 
parse_dos_attribute_blob(struct smb_filename * smb_fname,DATA_BLOB blob,uint32_t * pattr)265 NTSTATUS parse_dos_attribute_blob(struct smb_filename *smb_fname,
266 				  DATA_BLOB blob,
267 				  uint32_t *pattr)
268 {
269 	struct xattr_DOSATTRIB dosattrib;
270 	enum ndr_err_code ndr_err;
271 	uint32_t dosattr;
272 
273 	ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib,
274 			(ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB);
275 
276 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
277 		DBG_WARNING("bad ndr decode "
278 			    "from EA on file %s: Error = %s\n",
279 			    smb_fname_str_dbg(smb_fname),
280 			    ndr_errstr(ndr_err));
281 		return ndr_map_error2ntstatus(ndr_err);
282 	}
283 
284 	DBG_DEBUG("%s attr = %s\n",
285 		  smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex);
286 
287 	switch (dosattrib.version) {
288 	case 0xFFFF:
289 		dosattr = dosattrib.info.compatinfoFFFF.attrib;
290 		break;
291 	case 1:
292 		dosattr = dosattrib.info.info1.attrib;
293 		if (!null_nttime(dosattrib.info.info1.create_time)) {
294 			struct timespec create_time =
295 				nt_time_to_unix_timespec(
296 					dosattrib.info.info1.create_time);
297 
298 			update_stat_ex_create_time(&smb_fname->st,
299 						   create_time);
300 
301 			DBG_DEBUG("file %s case 1 set btime %s\n",
302 				  smb_fname_str_dbg(smb_fname),
303 				  time_to_asc(convert_timespec_to_time_t(
304 						      create_time)));
305 		}
306 		break;
307 	case 2:
308 		dosattr = dosattrib.info.oldinfo2.attrib;
309 		/* Don't know what flags to check for this case. */
310 		break;
311 	case 3:
312 		dosattr = dosattrib.info.info3.attrib;
313 		if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
314 		    !null_nttime(dosattrib.info.info3.create_time)) {
315 			struct timespec create_time =
316 				nt_time_to_full_timespec(
317 					dosattrib.info.info3.create_time);
318 
319 			update_stat_ex_create_time(&smb_fname->st,
320 						   create_time);
321 
322 			DBG_DEBUG("file %s case 3 set btime %s\n",
323 				  smb_fname_str_dbg(smb_fname),
324 				  time_to_asc(convert_timespec_to_time_t(
325 						      create_time)));
326 		}
327 		break;
328 	case 4:
329 	{
330 		struct xattr_DosInfo4 *info = &dosattrib.info.info4;
331 
332 		dosattr = info->attrib;
333 
334 		if ((info->valid_flags & XATTR_DOSINFO_CREATE_TIME) &&
335 		    !null_nttime(info->create_time))
336 		{
337 			struct timespec creat_time;
338 
339 			creat_time = nt_time_to_full_timespec(info->create_time);
340 			update_stat_ex_create_time(&smb_fname->st, creat_time);
341 
342 			DBG_DEBUG("file [%s] creation time [%s]\n",
343 				smb_fname_str_dbg(smb_fname),
344 				nt_time_string(talloc_tos(), info->create_time));
345 		}
346 
347 		if (info->valid_flags & XATTR_DOSINFO_ITIME) {
348 			struct timespec itime;
349 			uint64_t file_id;
350 
351 			itime = nt_time_to_unix_timespec(info->itime);
352 			if (smb_fname->st.st_ex_iflags &
353 			    ST_EX_IFLAG_CALCULATED_ITIME)
354 			{
355 				update_stat_ex_itime(&smb_fname->st, itime);
356 			}
357 
358 			file_id = make_file_id_from_itime(&smb_fname->st);
359 			if (smb_fname->st.st_ex_iflags &
360 			    ST_EX_IFLAG_CALCULATED_FILE_ID)
361 			{
362 				update_stat_ex_file_id(&smb_fname->st, file_id);
363 			}
364 
365 			DBG_DEBUG("file [%s] itime [%s] fileid [%"PRIx64"]\n",
366 				smb_fname_str_dbg(smb_fname),
367 				nt_time_string(talloc_tos(), info->itime),
368 				file_id);
369 		}
370 		break;
371 	}
372 	default:
373 		DBG_WARNING("Badly formed DOSATTRIB on file %s - %s\n",
374 			    smb_fname_str_dbg(smb_fname), blob.data);
375 		/* Should this be INTERNAL_ERROR? */
376 		return NT_STATUS_INVALID_PARAMETER;
377 	}
378 
379 	if (S_ISDIR(smb_fname->st.st_ex_mode)) {
380 		dosattr |= FILE_ATTRIBUTE_DIRECTORY;
381 	}
382 
383 	/* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
384 	*pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
385 
386 	dos_mode_debug_print(__func__, *pattr);
387 
388 	return NT_STATUS_OK;
389 }
390 
get_ea_dos_attribute(connection_struct * conn,struct smb_filename * smb_fname,uint32_t * pattr)391 NTSTATUS get_ea_dos_attribute(connection_struct *conn,
392 			      struct smb_filename *smb_fname,
393 			      uint32_t *pattr)
394 {
395 	DATA_BLOB blob;
396 	ssize_t sizeret;
397 	fstring attrstr;
398 	NTSTATUS status;
399 
400 	if (!lp_store_dos_attributes(SNUM(conn))) {
401 		return NT_STATUS_NOT_IMPLEMENTED;
402 	}
403 
404 	/* Don't reset pattr to zero as we may already have filename-based attributes we
405 	   need to preserve. */
406 
407 	sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
408 				   SAMBA_XATTR_DOS_ATTRIB, attrstr,
409 				   sizeof(attrstr));
410 	if (sizeret == -1 && errno == EACCES) {
411 		int saved_errno = 0;
412 
413 		/*
414 		 * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
415 		 * an Existing File" FILE_LIST_DIRECTORY on a directory implies
416 		 * FILE_READ_ATTRIBUTES for directory entries. Being able to
417 		 * stat() a file implies FILE_LIST_DIRECTORY for the directory
418 		 * containing the file.
419 		 */
420 
421 		if (!VALID_STAT(smb_fname->st)) {
422 			/*
423 			 * Safety net: dos_mode() already checks this, but as we
424 			 * become root based on this, add an additional layer of
425 			 * defense.
426 			 */
427 			DBG_ERR("Rejecting root override, invalid stat [%s]\n",
428 				smb_fname_str_dbg(smb_fname));
429 			return NT_STATUS_ACCESS_DENIED;
430 		}
431 
432 		become_root();
433 		sizeret = SMB_VFS_GETXATTR(conn, smb_fname,
434 					   SAMBA_XATTR_DOS_ATTRIB,
435 					   attrstr,
436 					   sizeof(attrstr));
437 		if (sizeret == -1) {
438 			saved_errno = errno;
439 		}
440 		unbecome_root();
441 
442 		if (saved_errno != 0) {
443 			errno = saved_errno;
444 		}
445 	}
446 	if (sizeret == -1) {
447 		DBG_INFO("Cannot get attribute "
448 			 "from EA on file %s: Error = %s\n",
449 			 smb_fname_str_dbg(smb_fname), strerror(errno));
450 		return map_nt_error_from_unix(errno);
451 	}
452 
453 	blob.data = (uint8_t *)attrstr;
454 	blob.length = sizeret;
455 
456 	status = parse_dos_attribute_blob(smb_fname, blob, pattr);
457 	if (!NT_STATUS_IS_OK(status)) {
458 		return status;
459 	}
460 
461 	return NT_STATUS_OK;
462 }
463 
464 /****************************************************************************
465  Set DOS attributes in an EA.
466  Also sets the create time.
467 ****************************************************************************/
468 
set_ea_dos_attribute(connection_struct * conn,const struct smb_filename * smb_fname,uint32_t dosmode)469 NTSTATUS set_ea_dos_attribute(connection_struct *conn,
470 			      const struct smb_filename *smb_fname,
471 			      uint32_t dosmode)
472 {
473 	struct xattr_DOSATTRIB dosattrib;
474 	enum ndr_err_code ndr_err;
475 	DATA_BLOB blob;
476 	int ret;
477 
478 	if (!lp_store_dos_attributes(SNUM(conn))) {
479 		return NT_STATUS_NOT_IMPLEMENTED;
480 	}
481 
482 	/*
483 	 * Don't store FILE_ATTRIBUTE_OFFLINE, it's dealt with in
484 	 * vfs_default via DMAPI if that is enabled.
485 	 */
486 	dosmode &= ~FILE_ATTRIBUTE_OFFLINE;
487 
488 	ZERO_STRUCT(dosattrib);
489 	ZERO_STRUCT(blob);
490 
491 	dosattrib.version = 4;
492 	dosattrib.info.info4.valid_flags = XATTR_DOSINFO_ATTRIB |
493 					XATTR_DOSINFO_CREATE_TIME;
494 	dosattrib.info.info4.attrib = dosmode;
495 	dosattrib.info.info4.create_time = full_timespec_to_nt_time(
496 		&smb_fname->st.st_ex_btime);
497 
498 	if (!(smb_fname->st.st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) {
499 		dosattrib.info.info4.valid_flags |= XATTR_DOSINFO_ITIME;
500 		dosattrib.info.info4.itime = full_timespec_to_nt_time(
501 			&smb_fname->st.st_ex_itime);
502 	}
503 
504 	DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n",
505 		(unsigned int)dosmode,
506 		time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)),
507 		smb_fname_str_dbg(smb_fname) ));
508 
509 	ndr_err = ndr_push_struct_blob(
510 			&blob, talloc_tos(), &dosattrib,
511 			(ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB);
512 
513 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
514 		DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n",
515 			ndr_errstr(ndr_err)));
516 		return ndr_map_error2ntstatus(ndr_err);
517 	}
518 
519 	if (blob.data == NULL || blob.length == 0) {
520 		/* Should this be INTERNAL_ERROR? */
521 		return NT_STATUS_INVALID_PARAMETER;
522 	}
523 
524 	ret = SMB_VFS_SETXATTR(conn, smb_fname,
525 			       SAMBA_XATTR_DOS_ATTRIB,
526 			       blob.data, blob.length, 0);
527 	if (ret != 0) {
528 		NTSTATUS status = NT_STATUS_OK;
529 		bool need_close = false;
530 		files_struct *fsp = NULL;
531 		bool set_dosmode_ok = false;
532 
533 		if ((errno != EPERM) && (errno != EACCES)) {
534 			DBG_INFO("Cannot set "
535 				 "attribute EA on file %s: Error = %s\n",
536 				 smb_fname_str_dbg(smb_fname), strerror(errno));
537 			return map_nt_error_from_unix(errno);
538 		}
539 
540 		/* We want DOS semantics, ie allow non owner with write permission to change the
541 			bits on a file. Just like file_ntimes below.
542 		*/
543 
544 		/* Check if we have write access. */
545 		if (!CAN_WRITE(conn)) {
546 			return NT_STATUS_ACCESS_DENIED;
547 		}
548 
549 		status = smbd_check_access_rights(conn, smb_fname, false,
550 						  FILE_WRITE_ATTRIBUTES);
551 		if (NT_STATUS_IS_OK(status)) {
552 			set_dosmode_ok = true;
553 		}
554 
555 		if (!set_dosmode_ok && lp_dos_filemode(SNUM(conn))) {
556 			set_dosmode_ok = can_write_to_file(conn, smb_fname);
557 		}
558 
559 		if (!set_dosmode_ok) {
560 			return NT_STATUS_ACCESS_DENIED;
561 		}
562 
563 		/*
564 		 * We need to get an open file handle to do the
565 		 * metadata operation under root.
566 		 */
567 
568 		status = get_file_handle_for_metadata(conn,
569 						smb_fname,
570 						&fsp,
571 						&need_close);
572 		if (!NT_STATUS_IS_OK(status)) {
573 			return status;
574 		}
575 
576 		become_root();
577 		ret = SMB_VFS_FSETXATTR(fsp,
578 					SAMBA_XATTR_DOS_ATTRIB,
579 					blob.data, blob.length, 0);
580 		if (ret == 0) {
581 			status = NT_STATUS_OK;
582 		}
583 		unbecome_root();
584 		if (need_close) {
585 			close_file(NULL, fsp, NORMAL_CLOSE);
586 		}
587 		return status;
588 	}
589 	DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n",
590 		(unsigned int)dosmode,
591 		smb_fname_str_dbg(smb_fname)));
592 	return NT_STATUS_OK;
593 }
594 
595 /****************************************************************************
596  Change a unix mode to a dos mode for an ms dfs link.
597 ****************************************************************************/
598 
dos_mode_msdfs(connection_struct * conn,const struct smb_filename * smb_fname)599 uint32_t dos_mode_msdfs(connection_struct *conn,
600 		      const struct smb_filename *smb_fname)
601 {
602 	uint32_t result = 0;
603 
604 	DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname)));
605 
606 	if (!VALID_STAT(smb_fname->st)) {
607 		return 0;
608 	}
609 
610 	/* First do any modifications that depend on the path name. */
611 	/* hide files with a name starting with a . */
612 	if (lp_hide_dot_files(SNUM(conn))) {
613 		const char *p = strrchr_m(smb_fname->base_name, '/');
614 		if (p) {
615 			p++;
616 		} else {
617 			p = smb_fname->base_name;
618 		}
619 
620 		/* Only . and .. are not hidden. */
621 		if (p[0] == '.' && !((p[1] == '\0') ||
622 				(p[1] == '.' && p[2] == '\0'))) {
623 			result |= FILE_ATTRIBUTE_HIDDEN;
624 		}
625 	}
626 
627 	result |= dos_mode_from_sbuf(conn, smb_fname);
628 
629 	/* Optimization : Only call is_hidden_path if it's not already
630 	   hidden. */
631 	if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
632 	    IS_HIDDEN_PATH(conn, smb_fname->base_name)) {
633 		result |= FILE_ATTRIBUTE_HIDDEN;
634 	}
635 
636 	if (result == 0) {
637 		result = FILE_ATTRIBUTE_NORMAL;
638 	}
639 
640 	result = filter_mode_by_protocol(result);
641 
642 	/*
643 	 * Add in that it is a reparse point
644 	 */
645 	result |= FILE_ATTRIBUTE_REPARSE_POINT;
646 
647 	dos_mode_debug_print(__func__, result);
648 
649 	return(result);
650 }
651 
652 /*
653  * check whether a file or directory is flagged as compressed.
654  */
dos_mode_check_compressed(connection_struct * conn,struct smb_filename * smb_fname,bool * is_compressed)655 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
656 					  struct smb_filename *smb_fname,
657 					  bool *is_compressed)
658 {
659 	NTSTATUS status;
660 	uint16_t compression_fmt;
661 	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
662 	if (tmp_ctx == NULL) {
663 		status = NT_STATUS_NO_MEMORY;
664 		goto err_out;
665 	}
666 
667 	status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
668 					 &compression_fmt);
669 	if (!NT_STATUS_IS_OK(status)) {
670 		goto err_ctx_free;
671 	}
672 
673 	if (compression_fmt == COMPRESSION_FORMAT_LZNT1) {
674 		*is_compressed = true;
675 	} else {
676 		*is_compressed = false;
677 	}
678 	status = NT_STATUS_OK;
679 
680 err_ctx_free:
681 	talloc_free(tmp_ctx);
682 err_out:
683 	return status;
684 }
685 
dos_mode_from_name(connection_struct * conn,const struct smb_filename * smb_fname,uint32_t dosmode)686 static uint32_t dos_mode_from_name(connection_struct *conn,
687 				   const struct smb_filename *smb_fname,
688 				   uint32_t dosmode)
689 {
690 	const char *p = NULL;
691 	uint32_t result = dosmode;
692 
693 	if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
694 	    lp_hide_dot_files(SNUM(conn)))
695 	{
696 		p = strrchr_m(smb_fname->base_name, '/');
697 		if (p) {
698 			p++;
699 		} else {
700 			p = smb_fname->base_name;
701 		}
702 
703 		/* Only . and .. are not hidden. */
704 		if ((p[0] == '.') &&
705 		    !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0')))
706 		{
707 			result |= FILE_ATTRIBUTE_HIDDEN;
708 		}
709 	}
710 
711 	if (!(result & FILE_ATTRIBUTE_HIDDEN) &&
712 	    IS_HIDDEN_PATH(conn, smb_fname->base_name))
713 	{
714 		result |= FILE_ATTRIBUTE_HIDDEN;
715 	}
716 
717 	return result;
718 }
719 
dos_mode_post(uint32_t dosmode,connection_struct * conn,struct smb_filename * smb_fname,const char * func)720 static uint32_t dos_mode_post(uint32_t dosmode,
721 			      connection_struct *conn,
722 			      struct smb_filename *smb_fname,
723 			      const char *func)
724 {
725 	NTSTATUS status;
726 
727 	/*
728 	 * According to MS-FSA a stream name does not have
729 	 * separate DOS attribute metadata, so we must return
730 	 * the DOS attribute from the base filename. With one caveat,
731 	 * a non-default stream name can never be a directory.
732 	 *
733 	 * As this is common to all streams data stores, we handle
734 	 * it here instead of inside all stream VFS modules.
735 	 *
736 	 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13380
737 	 */
738 
739 	if (is_named_stream(smb_fname)) {
740 		/* is_ntfs_stream_smb_fname() returns false for a POSIX path. */
741 		dosmode &= ~(FILE_ATTRIBUTE_DIRECTORY);
742 	}
743 
744 	if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
745 		bool compressed = false;
746 
747 		status = dos_mode_check_compressed(conn, smb_fname,
748 						   &compressed);
749 		if (NT_STATUS_IS_OK(status) && compressed) {
750 			dosmode |= FILE_ATTRIBUTE_COMPRESSED;
751 		}
752 	}
753 
754 	dosmode |= dos_mode_from_name(conn, smb_fname, dosmode);
755 
756 	if (S_ISDIR(smb_fname->st.st_ex_mode)) {
757 		dosmode |= FILE_ATTRIBUTE_DIRECTORY;
758 	} else if (dosmode == 0) {
759 		dosmode = FILE_ATTRIBUTE_NORMAL;
760 	}
761 
762 	dosmode = filter_mode_by_protocol(dosmode);
763 
764 	dos_mode_debug_print(func, dosmode);
765 	return dosmode;
766 }
767 
768 /****************************************************************************
769  Change a unix mode to a dos mode.
770  May also read the create timespec into the stat struct in smb_fname
771  if "store dos attributes" is true.
772 ****************************************************************************/
773 
dos_mode(connection_struct * conn,struct smb_filename * smb_fname)774 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
775 {
776 	uint32_t result = 0;
777 	NTSTATUS status = NT_STATUS_OK;
778 
779 	DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname)));
780 
781 	if (!VALID_STAT(smb_fname->st)) {
782 		return 0;
783 	}
784 
785 	/* Get the DOS attributes via the VFS if we can */
786 	status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &result);
787 	if (!NT_STATUS_IS_OK(status)) {
788 		/*
789 		 * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
790 		 */
791 		if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
792 			result |= dos_mode_from_sbuf(conn, smb_fname);
793 		}
794 	}
795 
796 	result = dos_mode_post(result, conn, smb_fname, __func__);
797 	return result;
798 }
799 
800 struct dos_mode_at_state {
801 	files_struct *dir_fsp;
802 	struct smb_filename *smb_fname;
803 	uint32_t dosmode;
804 };
805 
806 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq);
807 
dos_mode_at_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,files_struct * dir_fsp,struct smb_filename * smb_fname)808 struct tevent_req *dos_mode_at_send(TALLOC_CTX *mem_ctx,
809 				    struct tevent_context *ev,
810 				    files_struct *dir_fsp,
811 				    struct smb_filename *smb_fname)
812 {
813 	struct tevent_req *req = NULL;
814 	struct dos_mode_at_state *state = NULL;
815 	struct tevent_req *subreq = NULL;
816 
817 	DBG_DEBUG("%s\n", smb_fname_str_dbg(smb_fname));
818 
819 	req = tevent_req_create(mem_ctx, &state,
820 				struct dos_mode_at_state);
821 	if (req == NULL) {
822 		return NULL;
823 	}
824 
825 	*state = (struct dos_mode_at_state) {
826 		.dir_fsp = dir_fsp,
827 		.smb_fname = smb_fname,
828 	};
829 
830 	if (!VALID_STAT(smb_fname->st)) {
831 		tevent_req_done(req);
832 		return tevent_req_post(req, ev);
833 	}
834 
835 	subreq = SMB_VFS_GET_DOS_ATTRIBUTES_SEND(state,
836 						 ev,
837 						 dir_fsp,
838 						 smb_fname);
839 	if (tevent_req_nomem(subreq, req)) {
840 		return tevent_req_post(req, ev);
841 	}
842 	tevent_req_set_callback(subreq, dos_mode_at_vfs_get_dosmode_done, req);
843 
844 	return req;
845 }
846 
dos_mode_at_vfs_get_dosmode_done(struct tevent_req * subreq)847 static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
848 {
849 	struct tevent_req *req =
850 		tevent_req_callback_data(subreq,
851 		struct tevent_req);
852 	struct dos_mode_at_state *state =
853 		tevent_req_data(req,
854 		struct dos_mode_at_state);
855 	char *path = NULL;
856 	struct smb_filename *smb_path = NULL;
857 	struct vfs_aio_state aio_state;
858 	NTSTATUS status;
859 	bool ok;
860 
861 	/*
862 	 * Make sure we run as the user again
863 	 */
864 	ok = change_to_user_and_service_by_fsp(state->dir_fsp);
865 	SMB_ASSERT(ok);
866 
867 	status = SMB_VFS_GET_DOS_ATTRIBUTES_RECV(subreq,
868 						 &aio_state,
869 						 &state->dosmode);
870 	TALLOC_FREE(subreq);
871 	if (!NT_STATUS_IS_OK(status)) {
872 		/*
873 		 * Both the sync dos_mode() as well as the async
874 		 * dos_mode_at_[send|recv] have no real error return, the only
875 		 * unhandled error is when the stat info in smb_fname is not
876 		 * valid (cf the checks in dos_mode() and dos_mode_at_send().
877 		 *
878 		 * If SMB_VFS_GET_DOS_ATTRIBUTES[_SEND|_RECV] fails we must call
879 		 * dos_mode_post() which also does the mapping of a last ressort
880 		 * from S_IFMT(st_mode).
881 		 *
882 		 * Only if we get NT_STATUS_NOT_IMPLEMENTED from a stacked VFS
883 		 * module we must fallback to sync processing.
884 		 */
885 		if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
886 			/*
887 			 * state->dosmode should still be 0, but reset
888 			 * it to be sure.
889 			 */
890 			state->dosmode = 0;
891 			status = NT_STATUS_OK;
892 		}
893 	}
894 	if (NT_STATUS_IS_OK(status)) {
895 		state->dosmode = dos_mode_post(state->dosmode,
896 					       state->dir_fsp->conn,
897 					       state->smb_fname,
898 					       __func__);
899 		tevent_req_done(req);
900 		return;
901 	}
902 
903 	/*
904 	 * Fall back to sync dos_mode() if we got NOT_IMPLEMENTED.
905 	 */
906 
907 	path = talloc_asprintf(state,
908 			       "%s/%s",
909 			       state->dir_fsp->fsp_name->base_name,
910 			       state->smb_fname->base_name);
911 	if (tevent_req_nomem(path, req)) {
912 		return;
913 	}
914 
915 	smb_path = synthetic_smb_fname(state,
916 				       path,
917 				       NULL,
918 				       &state->smb_fname->st,
919 				       0);
920 	if (tevent_req_nomem(smb_path, req)) {
921 		return;
922 	}
923 
924 	state->dosmode = dos_mode(state->dir_fsp->conn, smb_path);
925 	tevent_req_done(req);
926 	return;
927 }
928 
dos_mode_at_recv(struct tevent_req * req,uint32_t * dosmode)929 NTSTATUS dos_mode_at_recv(struct tevent_req *req, uint32_t *dosmode)
930 {
931 	struct dos_mode_at_state *state =
932 		tevent_req_data(req,
933 		struct dos_mode_at_state);
934 	NTSTATUS status;
935 
936 	if (tevent_req_is_nterror(req, &status)) {
937 		tevent_req_received(req);
938 		return status;
939 	}
940 
941 	*dosmode = state->dosmode;
942 	tevent_req_received(req);
943 	return NT_STATUS_OK;
944 }
945 
946 /*******************************************************************
947  chmod a file - but preserve some bits.
948  If "store dos attributes" is also set it will store the create time
949  from the stat struct in smb_fname (in NTTIME format) in the EA
950  attribute also.
951 ********************************************************************/
952 
file_set_dosmode(connection_struct * conn,struct smb_filename * smb_fname,uint32_t dosmode,const char * parent_dir,bool newfile)953 int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname,
954 		     uint32_t dosmode, const char *parent_dir, bool newfile)
955 {
956 	int mask=0;
957 	mode_t tmp;
958 	mode_t unixmode;
959 	int ret = -1, lret = -1;
960 	files_struct *fsp = NULL;
961 	bool need_close = false;
962 	NTSTATUS status;
963 
964 	if (!CAN_WRITE(conn)) {
965 		errno = EROFS;
966 		return -1;
967 	}
968 
969 	dosmode &= SAMBA_ATTRIBUTES_MASK;
970 
971 	DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n",
972 		  dosmode, smb_fname_str_dbg(smb_fname)));
973 
974 	unixmode = smb_fname->st.st_ex_mode;
975 
976 	get_acl_group_bits(conn, smb_fname,
977 			&smb_fname->st.st_ex_mode);
978 
979 	if (S_ISDIR(smb_fname->st.st_ex_mode))
980 		dosmode |= FILE_ATTRIBUTE_DIRECTORY;
981 	else
982 		dosmode &= ~FILE_ATTRIBUTE_DIRECTORY;
983 
984 	/* Store the DOS attributes in an EA by preference. */
985 	status = SMB_VFS_SET_DOS_ATTRIBUTES(conn, smb_fname, dosmode);
986 	if (NT_STATUS_IS_OK(status)) {
987 		if (!newfile) {
988 			notify_fname(conn, NOTIFY_ACTION_MODIFIED,
989 				FILE_NOTIFY_CHANGE_ATTRIBUTES,
990 				smb_fname->base_name);
991 		}
992 		smb_fname->st.st_ex_mode = unixmode;
993 		return 0;
994 	} else {
995 		/*
996 		 * Only fall back to using UNIX modes if
997 		 * we get NOT_IMPLEMENTED.
998 		 */
999 		if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
1000 			errno = map_errno_from_nt_status(status);
1001 			return -1;
1002 		}
1003 	}
1004 
1005 	/* Fall back to UNIX modes. */
1006 	unixmode = unix_mode(conn, dosmode, smb_fname, parent_dir);
1007 
1008 	/* preserve the file type bits */
1009 	mask |= S_IFMT;
1010 
1011 	/* preserve the s bits */
1012 	mask |= (S_ISUID | S_ISGID);
1013 
1014 	/* preserve the t bit */
1015 #ifdef S_ISVTX
1016 	mask |= S_ISVTX;
1017 #endif
1018 
1019 	/* possibly preserve the x bits */
1020 	if (!MAP_ARCHIVE(conn))
1021 		mask |= S_IXUSR;
1022 	if (!MAP_SYSTEM(conn))
1023 		mask |= S_IXGRP;
1024 	if (!MAP_HIDDEN(conn))
1025 		mask |= S_IXOTH;
1026 
1027 	unixmode |= (smb_fname->st.st_ex_mode & mask);
1028 
1029 	/* if we previously had any r bits set then leave them alone */
1030 	if ((tmp = smb_fname->st.st_ex_mode & (S_IRUSR|S_IRGRP|S_IROTH))) {
1031 		unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
1032 		unixmode |= tmp;
1033 	}
1034 
1035 	/* if we previously had any w bits set then leave them alone
1036 		whilst adding in the new w bits, if the new mode is not rdonly */
1037 	if (!IS_DOS_READONLY(dosmode)) {
1038 		unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
1039 	}
1040 
1041 	/*
1042 	 * From the chmod 2 man page:
1043 	 *
1044 	 * "If the calling process is not privileged, and the group of the file
1045 	 * does not match the effective group ID of the process or one of its
1046 	 * supplementary group IDs, the S_ISGID bit will be turned off, but
1047 	 * this will not cause an error to be returned."
1048 	 *
1049 	 * Simply refuse to do the chmod in this case.
1050 	 */
1051 
1052 	if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) &&
1053 			geteuid() != sec_initial_uid() &&
1054 			!current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
1055 		DEBUG(3,("file_set_dosmode: setgid bit cannot be "
1056 			"set for directory %s\n",
1057 			smb_fname_str_dbg(smb_fname)));
1058 		errno = EPERM;
1059 		return -1;
1060 	}
1061 
1062 	ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
1063 	if (ret == 0) {
1064 		if(!newfile || (lret != -1)) {
1065 			notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1066 				     FILE_NOTIFY_CHANGE_ATTRIBUTES,
1067 				     smb_fname->base_name);
1068 		}
1069 		smb_fname->st.st_ex_mode = unixmode;
1070 		return 0;
1071 	}
1072 
1073 	if((errno != EPERM) && (errno != EACCES))
1074 		return -1;
1075 
1076 	if(!lp_dos_filemode(SNUM(conn)))
1077 		return -1;
1078 
1079 	/* We want DOS semantics, ie allow non owner with write permission to change the
1080 		bits on a file. Just like file_ntimes below.
1081 	*/
1082 
1083 	if (!can_write_to_file(conn, smb_fname)) {
1084 		errno = EACCES;
1085 		return -1;
1086 	}
1087 
1088 	/*
1089 	 * We need to get an open file handle to do the
1090 	 * metadata operation under root.
1091 	 */
1092 
1093 	status = get_file_handle_for_metadata(conn,
1094 					      smb_fname,
1095 					      &fsp,
1096 					      &need_close);
1097 	if (!NT_STATUS_IS_OK(status)) {
1098 		errno = map_errno_from_nt_status(status);
1099 		return -1;
1100 	}
1101 
1102 	become_root();
1103 	ret = SMB_VFS_FCHMOD(fsp, unixmode);
1104 	unbecome_root();
1105 	if (need_close) {
1106 		close_file(NULL, fsp, NORMAL_CLOSE);
1107 	}
1108 	if (!newfile) {
1109 		notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1110 			     FILE_NOTIFY_CHANGE_ATTRIBUTES,
1111 			     smb_fname->base_name);
1112 	}
1113 	if (ret == 0) {
1114 		smb_fname->st.st_ex_mode = unixmode;
1115 	}
1116 
1117 	return( ret );
1118 }
1119 
1120 
file_set_sparse(connection_struct * conn,files_struct * fsp,bool sparse)1121 NTSTATUS file_set_sparse(connection_struct *conn,
1122 			 files_struct *fsp,
1123 			 bool sparse)
1124 {
1125 	const struct loadparm_substitution *lp_sub =
1126 		loadparm_s3_global_substitution();
1127 	uint32_t old_dosmode;
1128 	uint32_t new_dosmode;
1129 	NTSTATUS status;
1130 
1131 	if (!CAN_WRITE(conn)) {
1132 		DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1133 			"on readonly share[%s]\n",
1134 			smb_fname_str_dbg(fsp->fsp_name),
1135 			sparse,
1136 			lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
1137 		return NT_STATUS_MEDIA_WRITE_PROTECTED;
1138 	}
1139 
1140 	/*
1141 	 * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the
1142 	 * following access flags are granted.
1143 	 */
1144 	if ((fsp->access_mask & (FILE_WRITE_DATA
1145 				| FILE_WRITE_ATTRIBUTES
1146 				| SEC_FILE_APPEND_DATA)) == 0) {
1147 		DEBUG(9,("file_set_sparse: fname[%s] set[%u] "
1148 			"access_mask[0x%08X] - access denied\n",
1149 			smb_fname_str_dbg(fsp->fsp_name),
1150 			sparse,
1151 			fsp->access_mask));
1152 		return NT_STATUS_ACCESS_DENIED;
1153 	}
1154 
1155 	if (fsp->is_directory) {
1156 		DEBUG(9, ("invalid attempt to %s sparse flag on dir %s\n",
1157 			  (sparse ? "set" : "clear"),
1158 			  smb_fname_str_dbg(fsp->fsp_name)));
1159 		return NT_STATUS_INVALID_PARAMETER;
1160 	}
1161 
1162 	if (IS_IPC(conn) || IS_PRINT(conn)) {
1163 		DEBUG(9, ("attempt to %s sparse flag over invalid conn\n",
1164 			  (sparse ? "set" : "clear")));
1165 		return NT_STATUS_INVALID_PARAMETER;
1166 	}
1167 
1168 	DEBUG(10,("file_set_sparse: setting sparse bit %u on file %s\n",
1169 		  sparse, smb_fname_str_dbg(fsp->fsp_name)));
1170 
1171 	if (!lp_store_dos_attributes(SNUM(conn))) {
1172 		return NT_STATUS_INVALID_DEVICE_REQUEST;
1173 	}
1174 
1175 	status = vfs_stat_fsp(fsp);
1176 	if (!NT_STATUS_IS_OK(status)) {
1177 		return status;
1178 	}
1179 
1180 	old_dosmode = dos_mode(conn, fsp->fsp_name);
1181 
1182 	if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1183 		new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
1184 	} else if (!sparse && (old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
1185 		new_dosmode = old_dosmode & ~FILE_ATTRIBUTE_SPARSE;
1186 	} else {
1187 		return NT_STATUS_OK;
1188 	}
1189 
1190 	/* Store the DOS attributes in an EA. */
1191 	status = SMB_VFS_FSET_DOS_ATTRIBUTES(conn, fsp, new_dosmode);
1192 	if (!NT_STATUS_IS_OK(status)) {
1193 		return status;
1194 	}
1195 
1196 	notify_fname(conn, NOTIFY_ACTION_MODIFIED,
1197 		     FILE_NOTIFY_CHANGE_ATTRIBUTES,
1198 		     fsp->fsp_name->base_name);
1199 
1200 	fsp->is_sparse = sparse;
1201 
1202 	return NT_STATUS_OK;
1203 }
1204 
1205 /*******************************************************************
1206  Wrapper around the VFS ntimes that possibly allows DOS semantics rather
1207  than POSIX.
1208 *******************************************************************/
1209 
file_ntimes(connection_struct * conn,const struct smb_filename * smb_fname,struct smb_file_time * ft)1210 int file_ntimes(connection_struct *conn, const struct smb_filename *smb_fname,
1211 		struct smb_file_time *ft)
1212 {
1213 	int ret = -1;
1214 
1215 	errno = 0;
1216 
1217 	DEBUG(6, ("file_ntime: actime: %s",
1218 		  time_to_asc(convert_timespec_to_time_t(ft->atime))));
1219 	DEBUG(6, ("file_ntime: modtime: %s",
1220 		  time_to_asc(convert_timespec_to_time_t(ft->mtime))));
1221 	DEBUG(6, ("file_ntime: ctime: %s",
1222 		  time_to_asc(convert_timespec_to_time_t(ft->ctime))));
1223 	DEBUG(6, ("file_ntime: createtime: %s",
1224 		  time_to_asc(convert_timespec_to_time_t(ft->create_time))));
1225 
1226 	/* Don't update the time on read-only shares */
1227 	/* We need this as set_filetime (which can be called on
1228 	   close and other paths) can end up calling this function
1229 	   without the NEED_WRITE protection. Found by :
1230 	   Leo Weppelman <leo@wau.mis.ah.nl>
1231 	*/
1232 
1233 	if (!CAN_WRITE(conn)) {
1234 		return 0;
1235 	}
1236 
1237 	if(SMB_VFS_NTIMES(conn, smb_fname, ft) == 0) {
1238 		return 0;
1239 	}
1240 
1241 	if((errno != EPERM) && (errno != EACCES)) {
1242 		return -1;
1243 	}
1244 
1245 	if(!lp_dos_filetimes(SNUM(conn))) {
1246 		return -1;
1247 	}
1248 
1249 	/* We have permission (given by the Samba admin) to
1250 	   break POSIX semantics and allow a user to change
1251 	   the time on a file they don't own but can write to
1252 	   (as DOS does).
1253 	 */
1254 
1255 	/* Check if we have write access. */
1256 	if (can_write_to_file(conn, smb_fname)) {
1257 		/* We are allowed to become root and change the filetime. */
1258 		become_root();
1259 		ret = SMB_VFS_NTIMES(conn, smb_fname, ft);
1260 		unbecome_root();
1261 	}
1262 
1263 	return ret;
1264 }
1265 
1266 /******************************************************************
1267  Force a "sticky" write time on a pathname. This will always be
1268  returned on all future write time queries and set on close.
1269 ******************************************************************/
1270 
set_sticky_write_time_path(struct file_id fileid,struct timespec mtime)1271 bool set_sticky_write_time_path(struct file_id fileid, struct timespec mtime)
1272 {
1273 	if (is_omit_timespec(&mtime)) {
1274 		return true;
1275 	}
1276 
1277 	if (!set_sticky_write_time(fileid, mtime)) {
1278 		return false;
1279 	}
1280 
1281 	return true;
1282 }
1283 
1284 /******************************************************************
1285  Force a "sticky" write time on an fsp. This will always be
1286  returned on all future write time queries and set on close.
1287 ******************************************************************/
1288 
set_sticky_write_time_fsp(struct files_struct * fsp,struct timespec mtime)1289 bool set_sticky_write_time_fsp(struct files_struct *fsp, struct timespec mtime)
1290 {
1291 	if (is_omit_timespec(&mtime)) {
1292 		return true;
1293 	}
1294 
1295 	fsp->write_time_forced = true;
1296 	TALLOC_FREE(fsp->update_write_time_event);
1297 
1298 	return set_sticky_write_time_path(fsp->file_id, mtime);
1299 }
1300 
1301 /******************************************************************
1302  Set a create time EA.
1303 ******************************************************************/
1304 
set_create_timespec_ea(connection_struct * conn,const struct smb_filename * psmb_fname,struct timespec create_time)1305 NTSTATUS set_create_timespec_ea(connection_struct *conn,
1306 				const struct smb_filename *psmb_fname,
1307 				struct timespec create_time)
1308 {
1309 	struct smb_filename *smb_fname;
1310 	uint32_t dosmode;
1311 	int ret;
1312 
1313 	if (!lp_store_dos_attributes(SNUM(conn))) {
1314 		return NT_STATUS_OK;
1315 	}
1316 
1317 	smb_fname = synthetic_smb_fname(talloc_tos(),
1318 					psmb_fname->base_name,
1319 					NULL,
1320 					&psmb_fname->st,
1321 					psmb_fname->flags);
1322 
1323 	if (smb_fname == NULL) {
1324 		return NT_STATUS_NO_MEMORY;
1325 	}
1326 
1327 	dosmode = dos_mode(conn, smb_fname);
1328 
1329 	smb_fname->st.st_ex_btime = create_time;
1330 
1331 	ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
1332 	if (ret == -1) {
1333 		return map_nt_error_from_unix(errno);
1334 	}
1335 
1336 	DEBUG(10,("set_create_timespec_ea: wrote create time EA for file %s\n",
1337 		smb_fname_str_dbg(smb_fname)));
1338 
1339 	return NT_STATUS_OK;
1340 }
1341 
1342 /******************************************************************
1343  Return a create time.
1344 ******************************************************************/
1345 
get_create_timespec(connection_struct * conn,struct files_struct * fsp,const struct smb_filename * smb_fname)1346 struct timespec get_create_timespec(connection_struct *conn,
1347 				struct files_struct *fsp,
1348 				const struct smb_filename *smb_fname)
1349 {
1350 	return smb_fname->st.st_ex_btime;
1351 }
1352 
1353 /******************************************************************
1354  Return a change time (may look at EA in future).
1355 ******************************************************************/
1356 
get_change_timespec(connection_struct * conn,struct files_struct * fsp,const struct smb_filename * smb_fname)1357 struct timespec get_change_timespec(connection_struct *conn,
1358 				struct files_struct *fsp,
1359 				const struct smb_filename *smb_fname)
1360 {
1361 	return smb_fname->st.st_ex_mtime;
1362 }
1363 
1364 /****************************************************************************
1365  Get a real open file handle we can do meta-data operations on. As it's
1366  going to be used under root access only on meta-data we should look for
1367  any existing open file handle first, and use that in preference (also to
1368  avoid kernel self-oplock breaks). If not use an INTERNAL_OPEN_ONLY handle.
1369 ****************************************************************************/
1370 
get_file_handle_for_metadata(connection_struct * conn,const struct smb_filename * smb_fname,files_struct ** ret_fsp,bool * need_close)1371 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
1372 				const struct smb_filename *smb_fname,
1373 				files_struct **ret_fsp,
1374 				bool *need_close)
1375 {
1376 	NTSTATUS status;
1377 	files_struct *fsp;
1378 	struct file_id file_id;
1379 	struct smb_filename *smb_fname_cp = NULL;
1380 
1381 	*need_close = false;
1382 
1383 	if (!VALID_STAT(smb_fname->st)) {
1384 		return NT_STATUS_INVALID_PARAMETER;
1385 	}
1386 
1387 	file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1388 
1389 	for(fsp = file_find_di_first(conn->sconn, file_id);
1390 			fsp;
1391 			fsp = file_find_di_next(fsp)) {
1392 		if (fsp->fh->fd != -1) {
1393 			*ret_fsp = fsp;
1394 			return NT_STATUS_OK;
1395 		}
1396 	}
1397 
1398 	smb_fname_cp = cp_smb_filename(talloc_tos(),
1399 					smb_fname);
1400 	if (smb_fname_cp == NULL) {
1401 		return NT_STATUS_NO_MEMORY;
1402 	}
1403 
1404 	/* Opens an INTERNAL_OPEN_ONLY write handle. */
1405 	status = SMB_VFS_CREATE_FILE(
1406 		conn,                                   /* conn */
1407 		NULL,                                   /* req */
1408 		0,                                      /* root_dir_fid */
1409 		smb_fname_cp,				/* fname */
1410 		FILE_WRITE_ATTRIBUTES,			/* access_mask */
1411 		(FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
1412 			FILE_SHARE_DELETE),
1413 		FILE_OPEN,                              /* create_disposition*/
1414 		0,                                      /* create_options */
1415 		0,                                      /* file_attributes */
1416 		INTERNAL_OPEN_ONLY,                     /* oplock_request */
1417 		NULL,					/* lease */
1418                 0,                                      /* allocation_size */
1419 		0,                                      /* private_flags */
1420 		NULL,                                   /* sd */
1421 		NULL,                                   /* ea_list */
1422 		ret_fsp,                                /* result */
1423 		NULL,                                   /* pinfo */
1424 		NULL, NULL);				/* create context */
1425 
1426 	TALLOC_FREE(smb_fname_cp);
1427 
1428 	if (NT_STATUS_IS_OK(status)) {
1429 		*need_close = true;
1430 	}
1431 	return status;
1432 }
1433