1 /*
2  * Store streams in a separate subdirectory
3  *
4  * Copyright (C) Volker Lendecke, 2007
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "system/filesys.h"
23 
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_VFS
26 
27 /*
28  * Excerpt from a mail from tridge:
29  *
30  * Volker, what I'm thinking of is this:
31  * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream1
32  * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream2
33  *
34  * where XX/YY is a 2 level hash based on the fsid/inode. "aaaa.bbbb"
35  * is the fsid/inode. "namedstreamX" is a file named after the stream
36  * name.
37  */
38 
hash_fn(DATA_BLOB key)39 static uint32_t hash_fn(DATA_BLOB key)
40 {
41 	uint32_t value;	/* Used to compute the hash value.  */
42 	uint32_t i;	/* Used to cycle through random values. */
43 
44 	/* Set the initial value from the key size. */
45 	for (value = 0x238F13AF * key.length, i=0; i < key.length; i++)
46 		value = (value + (key.data[i] << (i*5 % 24)));
47 
48 	return (1103515243 * value + 12345);
49 }
50 
51 /*
52  * With the hashing scheme based on the inode we need to protect against
53  * streams showing up on files with re-used inodes. This can happen if we
54  * create a stream directory from within Samba, and a local process or NFS
55  * client deletes the file without deleting the streams directory. When the
56  * inode is re-used and the stream directory is still around, the streams in
57  * there would be show up as belonging to the new file.
58  *
59  * There are several workarounds for this, probably the easiest one is on
60  * systems which have a true birthtime stat element: When the file has a later
61  * birthtime than the streams directory, then we have to recreate the
62  * directory.
63  *
64  * The other workaround is to somehow mark the file as generated by Samba with
65  * something that a NFS client would not do. The closest one is a special
66  * xattr value being set. On systems which do not support xattrs, it might be
67  * an option to put in a special ACL entry for a non-existing group.
68  */
69 
file_is_valid(vfs_handle_struct * handle,const struct smb_filename * smb_fname)70 static bool file_is_valid(vfs_handle_struct *handle,
71 			const struct smb_filename *smb_fname)
72 {
73 	char buf;
74 
75 	DEBUG(10, ("file_is_valid (%s) called\n", smb_fname->base_name));
76 
77 	if (SMB_VFS_GETXATTR(handle->conn, smb_fname, SAMBA_XATTR_MARKER,
78 				  &buf, sizeof(buf)) != sizeof(buf)) {
79 		DEBUG(10, ("GETXATTR failed: %s\n", strerror(errno)));
80 		return false;
81 	}
82 
83 	if (buf != '1') {
84 		DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
85 		return false;
86 	}
87 
88 	return true;
89 }
90 
mark_file_valid(vfs_handle_struct * handle,const struct smb_filename * smb_fname)91 static bool mark_file_valid(vfs_handle_struct *handle,
92 				const struct smb_filename *smb_fname)
93 {
94 	char buf = '1';
95 	int ret;
96 
97 	DEBUG(10, ("marking file %s as valid\n", smb_fname->base_name));
98 
99 	ret = SMB_VFS_SETXATTR(handle->conn, smb_fname, SAMBA_XATTR_MARKER,
100 				    &buf, sizeof(buf), 0);
101 
102 	if (ret == -1) {
103 		DEBUG(10, ("SETXATTR failed: %s\n", strerror(errno)));
104 		return false;
105 	}
106 
107 	return true;
108 }
109 
110 /**
111  * Given an smb_filename, determine the stream directory using the file's
112  * base_name.
113  */
stream_dir(vfs_handle_struct * handle,const struct smb_filename * smb_fname,const SMB_STRUCT_STAT * base_sbuf,bool create_it)114 static char *stream_dir(vfs_handle_struct *handle,
115 			const struct smb_filename *smb_fname,
116 			const SMB_STRUCT_STAT *base_sbuf, bool create_it)
117 {
118 	const struct loadparm_substitution *lp_sub =
119 		loadparm_s3_global_substitution();
120 	uint32_t hash;
121 	struct smb_filename *smb_fname_hash = NULL;
122 	char *result = NULL;
123 	SMB_STRUCT_STAT base_sbuf_tmp;
124 	uint8_t first, second;
125 	char *tmp;
126 	char *id_hex;
127 	struct file_id id;
128 	uint8_t id_buf[16];
129 	bool check_valid;
130 	char *rootdir = NULL;
131 	struct smb_filename *rootdir_fname = NULL;
132 	struct smb_filename *tmp_fname = NULL;
133 	int ret;
134 
135 	check_valid = lp_parm_bool(SNUM(handle->conn),
136 		      "streams_depot", "check_valid", true);
137 
138 	tmp = talloc_asprintf(talloc_tos(), "%s/.streams",
139 		handle->conn->connectpath);
140 
141 	if (tmp == NULL) {
142 		errno = ENOMEM;
143 		goto fail;
144 	}
145 
146 	rootdir = lp_parm_substituted_string(talloc_tos(), lp_sub,
147 		SNUM(handle->conn), "streams_depot", "directory",
148 		tmp);
149 	if (rootdir == NULL) {
150 		errno = ENOMEM;
151 		goto fail;
152 	}
153 
154 	rootdir_fname = synthetic_smb_fname(talloc_tos(),
155 					rootdir,
156 					NULL,
157 					NULL,
158 					smb_fname->flags);
159 	if (rootdir_fname == NULL) {
160 		errno = ENOMEM;
161 		goto fail;
162 	}
163 
164 	/* Stat the base file if it hasn't already been done. */
165 	if (base_sbuf == NULL) {
166 		struct smb_filename *smb_fname_base;
167 
168 		smb_fname_base = synthetic_smb_fname(
169 					talloc_tos(),
170 					smb_fname->base_name,
171 					NULL,
172 					NULL,
173 					smb_fname->flags);
174 		if (smb_fname_base == NULL) {
175 			errno = ENOMEM;
176 			goto fail;
177 		}
178 		if (SMB_VFS_NEXT_STAT(handle, smb_fname_base) == -1) {
179 			TALLOC_FREE(smb_fname_base);
180 			goto fail;
181 		}
182 		base_sbuf_tmp = smb_fname_base->st;
183 		TALLOC_FREE(smb_fname_base);
184 	} else {
185 		base_sbuf_tmp = *base_sbuf;
186 	}
187 
188 	id = SMB_VFS_FILE_ID_CREATE(handle->conn, &base_sbuf_tmp);
189 
190 	push_file_id_16((char *)id_buf, &id);
191 
192 	hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
193 
194 	first = hash & 0xff;
195 	second = (hash >> 8) & 0xff;
196 
197 	id_hex = hex_encode_talloc(talloc_tos(), id_buf, sizeof(id_buf));
198 
199 	if (id_hex == NULL) {
200 		errno = ENOMEM;
201 		goto fail;
202 	}
203 
204 	result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
205 				 first, second, id_hex);
206 
207 	TALLOC_FREE(id_hex);
208 
209 	if (result == NULL) {
210 		errno = ENOMEM;
211 		return NULL;
212 	}
213 
214 	smb_fname_hash = synthetic_smb_fname(talloc_tos(),
215 					result,
216 					NULL,
217 					NULL,
218 					smb_fname->flags);
219 	if (smb_fname_hash == NULL) {
220 		errno = ENOMEM;
221 		goto fail;
222 	}
223 
224 	if (SMB_VFS_NEXT_STAT(handle, smb_fname_hash) == 0) {
225 		struct smb_filename *smb_fname_new = NULL;
226 		char *newname;
227 		bool delete_lost;
228 
229 		if (!S_ISDIR(smb_fname_hash->st.st_ex_mode)) {
230 			errno = EINVAL;
231 			goto fail;
232 		}
233 
234 		if (!check_valid ||
235 		    file_is_valid(handle, smb_fname)) {
236 			return result;
237 		}
238 
239 		/*
240 		 * Someone has recreated a file under an existing inode
241 		 * without deleting the streams directory.
242 		 * Move it away or remove if streams_depot:delete_lost is set.
243 		 */
244 
245 	again:
246 		delete_lost = lp_parm_bool(SNUM(handle->conn), "streams_depot",
247 					   "delete_lost", false);
248 
249 		if (delete_lost) {
250 			DEBUG(3, ("Someone has recreated a file under an "
251 			      "existing inode. Removing: %s\n",
252 			      smb_fname_hash->base_name));
253 			recursive_rmdir(talloc_tos(), handle->conn,
254 					smb_fname_hash);
255 			SMB_VFS_NEXT_UNLINKAT(handle,
256 					handle->conn->cwd_fsp,
257 					smb_fname_hash,
258 					AT_REMOVEDIR);
259 		} else {
260 			newname = talloc_asprintf(talloc_tos(), "lost-%lu",
261 						  random());
262 			DEBUG(3, ("Someone has recreated a file under an "
263 			      "existing inode. Renaming: %s to: %s\n",
264 			      smb_fname_hash->base_name,
265 			      newname));
266 			if (newname == NULL) {
267 				errno = ENOMEM;
268 				goto fail;
269 			}
270 
271 			smb_fname_new = synthetic_smb_fname(
272 						talloc_tos(),
273 						newname,
274 						NULL,
275 						NULL,
276 						smb_fname->flags);
277 			TALLOC_FREE(newname);
278 			if (smb_fname_new == NULL) {
279 				errno = ENOMEM;
280 				goto fail;
281 			}
282 
283 			if (SMB_VFS_NEXT_RENAMEAT(handle,
284 					handle->conn->cwd_fsp,
285 					smb_fname_hash,
286 					handle->conn->cwd_fsp,
287 					smb_fname_new) == -1) {
288 				TALLOC_FREE(smb_fname_new);
289 				if ((errno == EEXIST) || (errno == ENOTEMPTY)) {
290 					goto again;
291 				}
292 				goto fail;
293 			}
294 
295 			TALLOC_FREE(smb_fname_new);
296 		}
297 	}
298 
299 	if (!create_it) {
300 		errno = ENOENT;
301 		goto fail;
302 	}
303 
304 	ret = SMB_VFS_NEXT_MKDIRAT(handle,
305 				handle->conn->cwd_fsp,
306 				rootdir_fname,
307 				0755);
308 	if ((ret != 0) && (errno != EEXIST)) {
309 		goto fail;
310 	}
311 
312 	tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
313 	if (tmp == NULL) {
314 		errno = ENOMEM;
315 		goto fail;
316 	}
317 
318 	tmp_fname = synthetic_smb_fname(talloc_tos(),
319 					tmp,
320 					NULL,
321 					NULL,
322 					smb_fname->flags);
323 	if (tmp_fname == NULL) {
324 		errno = ENOMEM;
325 		goto fail;
326 	}
327 
328 	ret = SMB_VFS_NEXT_MKDIRAT(handle,
329 				handle->conn->cwd_fsp,
330 				tmp_fname,
331 				0755);
332 	if ((ret != 0) && (errno != EEXIST)) {
333 		goto fail;
334 	}
335 
336 	TALLOC_FREE(tmp);
337 	TALLOC_FREE(tmp_fname);
338 
339 	tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
340 			      second);
341 	if (tmp == NULL) {
342 		errno = ENOMEM;
343 		goto fail;
344 	}
345 
346 	tmp_fname = synthetic_smb_fname(talloc_tos(),
347 					tmp,
348 					NULL,
349 					NULL,
350 					smb_fname->flags);
351 	if (tmp_fname == NULL) {
352 		errno = ENOMEM;
353 		goto fail;
354 	}
355 
356 	ret = SMB_VFS_NEXT_MKDIRAT(handle,
357 			handle->conn->cwd_fsp,
358 			tmp_fname,
359 			0755);
360 	if ((ret != 0) && (errno != EEXIST)) {
361 		goto fail;
362 	}
363 
364 	TALLOC_FREE(tmp);
365 	TALLOC_FREE(tmp_fname);
366 
367 	/* smb_fname_hash is the struct smb_filename version of 'result' */
368 	ret = SMB_VFS_NEXT_MKDIRAT(handle,
369 			handle->conn->cwd_fsp,
370 			smb_fname_hash,
371 			0755);
372 	if ((ret != 0) && (errno != EEXIST)) {
373 		goto fail;
374 	}
375 
376 	if (check_valid && !mark_file_valid(handle, smb_fname)) {
377 		goto fail;
378 	}
379 
380 	TALLOC_FREE(rootdir_fname);
381 	TALLOC_FREE(rootdir);
382 	TALLOC_FREE(tmp_fname);
383 	TALLOC_FREE(smb_fname_hash);
384 	return result;
385 
386  fail:
387 	TALLOC_FREE(rootdir_fname);
388 	TALLOC_FREE(rootdir);
389 	TALLOC_FREE(tmp_fname);
390 	TALLOC_FREE(smb_fname_hash);
391 	TALLOC_FREE(result);
392 	return NULL;
393 }
394 /**
395  * Given a stream name, populate smb_fname_out with the actual location of the
396  * stream.
397  */
stream_smb_fname(vfs_handle_struct * handle,const struct smb_filename * smb_fname,struct smb_filename ** smb_fname_out,bool create_dir)398 static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
399 				 const struct smb_filename *smb_fname,
400 				 struct smb_filename **smb_fname_out,
401 				 bool create_dir)
402 {
403 	char *dirname, *stream_fname;
404 	const char *stype;
405 	NTSTATUS status;
406 
407 	*smb_fname_out = NULL;
408 
409 	stype = strchr_m(smb_fname->stream_name + 1, ':');
410 
411 	if (stype) {
412 		if (strcasecmp_m(stype, ":$DATA") != 0) {
413 			return NT_STATUS_INVALID_PARAMETER;
414 		}
415 	}
416 
417 	dirname = stream_dir(handle, smb_fname, NULL, create_dir);
418 
419 	if (dirname == NULL) {
420 		status = map_nt_error_from_unix(errno);
421 		goto fail;
422 	}
423 
424 	stream_fname = talloc_asprintf(talloc_tos(), "%s/%s", dirname,
425 				       smb_fname->stream_name);
426 
427 	if (stream_fname == NULL) {
428 		status = NT_STATUS_NO_MEMORY;
429 		goto fail;
430 	}
431 
432 	if (stype == NULL) {
433 		/* Append an explicit stream type if one wasn't specified. */
434 		stream_fname = talloc_asprintf(talloc_tos(), "%s:$DATA",
435 					       stream_fname);
436 		if (stream_fname == NULL) {
437 			status = NT_STATUS_NO_MEMORY;
438 			goto fail;
439 		}
440 	} else {
441 		/* Normalize the stream type to upercase. */
442 		if (!strupper_m(strrchr_m(stream_fname, ':') + 1)) {
443 			status = NT_STATUS_INVALID_PARAMETER;
444 			goto fail;
445 		}
446 	}
447 
448 	DEBUG(10, ("stream filename = %s\n", stream_fname));
449 
450 	/* Create an smb_filename with stream_name == NULL. */
451 	*smb_fname_out = synthetic_smb_fname(talloc_tos(),
452 					stream_fname,
453 					NULL,
454 					NULL,
455 					smb_fname->flags);
456 	if (*smb_fname_out == NULL) {
457 		return NT_STATUS_NO_MEMORY;
458 	}
459 
460 	return NT_STATUS_OK;
461 
462  fail:
463 	DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
464 	TALLOC_FREE(*smb_fname_out);
465 	return status;
466 }
467 
walk_streams(vfs_handle_struct * handle,struct smb_filename * smb_fname_base,char ** pdirname,bool (* fn)(const char * dirname,const char * dirent,void * private_data),void * private_data)468 static NTSTATUS walk_streams(vfs_handle_struct *handle,
469 			     struct smb_filename *smb_fname_base,
470 			     char **pdirname,
471 			     bool (*fn)(const char *dirname,
472 					const char *dirent,
473 					void *private_data),
474 			     void *private_data)
475 {
476 	char *dirname;
477 	struct smb_filename *dir_smb_fname = NULL;
478 	DIR *dirhandle = NULL;
479 	const char *dirent = NULL;
480 	char *talloced = NULL;
481 
482 	dirname = stream_dir(handle, smb_fname_base, &smb_fname_base->st,
483 			     false);
484 
485 	if (dirname == NULL) {
486 		if (errno == ENOENT) {
487 			/*
488 			 * no stream around
489 			 */
490 			return NT_STATUS_OK;
491 		}
492 		return map_nt_error_from_unix(errno);
493 	}
494 
495 	DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
496 
497 	dir_smb_fname = synthetic_smb_fname(talloc_tos(),
498 					dirname,
499 					NULL,
500 					NULL,
501 					smb_fname_base->flags);
502 	if (dir_smb_fname == NULL) {
503 		TALLOC_FREE(dirname);
504 		return NT_STATUS_NO_MEMORY;
505 	}
506 
507 	dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dir_smb_fname, NULL, 0);
508 
509 	TALLOC_FREE(dir_smb_fname);
510 
511 	if (dirhandle == NULL) {
512 		TALLOC_FREE(dirname);
513 		return map_nt_error_from_unix(errno);
514 	}
515 
516 	while ((dirent = vfs_readdirname(handle->conn, dirhandle, NULL,
517 					 &talloced)) != NULL) {
518 
519 		if (ISDOT(dirent) || ISDOTDOT(dirent)) {
520 			TALLOC_FREE(talloced);
521 			continue;
522 		}
523 
524 		DEBUG(10, ("walk_streams: dirent=%s\n", dirent));
525 
526 		if (!fn(dirname, dirent, private_data)) {
527 			TALLOC_FREE(talloced);
528 			break;
529 		}
530 		TALLOC_FREE(talloced);
531 	}
532 
533 	SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle);
534 
535 	if (pdirname != NULL) {
536 		*pdirname = dirname;
537 	}
538 	else {
539 		TALLOC_FREE(dirname);
540 	}
541 
542 	return NT_STATUS_OK;
543 }
544 
streams_depot_stat(vfs_handle_struct * handle,struct smb_filename * smb_fname)545 static int streams_depot_stat(vfs_handle_struct *handle,
546 			      struct smb_filename *smb_fname)
547 {
548 	struct smb_filename *smb_fname_stream = NULL;
549 	NTSTATUS status;
550 	int ret = -1;
551 
552 	DEBUG(10, ("streams_depot_stat called for [%s]\n",
553 		   smb_fname_str_dbg(smb_fname)));
554 
555 	if (!is_named_stream(smb_fname)) {
556 		return SMB_VFS_NEXT_STAT(handle, smb_fname);
557 	}
558 
559 	/* Stat the actual stream now. */
560 	status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
561 				  false);
562 	if (!NT_STATUS_IS_OK(status)) {
563 		ret = -1;
564 		errno = map_errno_from_nt_status(status);
565 		goto done;
566 	}
567 
568 	ret = SMB_VFS_NEXT_STAT(handle, smb_fname_stream);
569 
570 	/* Update the original smb_fname with the stat info. */
571 	smb_fname->st = smb_fname_stream->st;
572  done:
573 	TALLOC_FREE(smb_fname_stream);
574 	return ret;
575 }
576 
577 
578 
streams_depot_lstat(vfs_handle_struct * handle,struct smb_filename * smb_fname)579 static int streams_depot_lstat(vfs_handle_struct *handle,
580 			       struct smb_filename *smb_fname)
581 {
582 	struct smb_filename *smb_fname_stream = NULL;
583 	NTSTATUS status;
584 	int ret = -1;
585 
586 	DEBUG(10, ("streams_depot_lstat called for [%s]\n",
587 		   smb_fname_str_dbg(smb_fname)));
588 
589 	if (!is_named_stream(smb_fname)) {
590 		return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
591 	}
592 
593 	/* Stat the actual stream now. */
594 	status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
595 				  false);
596 	if (!NT_STATUS_IS_OK(status)) {
597 		ret = -1;
598 		errno = map_errno_from_nt_status(status);
599 		goto done;
600 	}
601 
602 	ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_stream);
603 
604  done:
605 	TALLOC_FREE(smb_fname_stream);
606 	return ret;
607 }
608 
streams_depot_open(vfs_handle_struct * handle,struct smb_filename * smb_fname,files_struct * fsp,int flags,mode_t mode)609 static int streams_depot_open(vfs_handle_struct *handle,
610 			      struct smb_filename *smb_fname,
611 			      files_struct *fsp, int flags, mode_t mode)
612 {
613 	struct smb_filename *smb_fname_stream = NULL;
614 	struct smb_filename *smb_fname_base = NULL;
615 	NTSTATUS status;
616 	int ret = -1;
617 
618 	if (!is_named_stream(smb_fname)) {
619 		return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
620 	}
621 
622 	/* Ensure the base file still exists. */
623 	smb_fname_base = synthetic_smb_fname(talloc_tos(),
624 					smb_fname->base_name,
625 					NULL,
626 					NULL,
627 					smb_fname->flags);
628 	if (smb_fname_base == NULL) {
629 		ret = -1;
630 		errno = ENOMEM;
631 		goto done;
632 	}
633 
634 	ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
635 	if (ret == -1) {
636 		goto done;
637 	}
638 
639 	/* Determine the stream name, and then open it. */
640 	status = stream_smb_fname(handle, smb_fname, &smb_fname_stream, true);
641 	if (!NT_STATUS_IS_OK(status)) {
642 		ret = -1;
643 		errno = map_errno_from_nt_status(status);
644 		goto done;
645 	}
646 
647 	ret = SMB_VFS_NEXT_OPEN(handle, smb_fname_stream, fsp, flags, mode);
648 
649  done:
650 	TALLOC_FREE(smb_fname_stream);
651 	TALLOC_FREE(smb_fname_base);
652 	return ret;
653 }
654 
streams_depot_unlink_internal(vfs_handle_struct * handle,struct files_struct * dirfsp,const struct smb_filename * smb_fname,int flags)655 static int streams_depot_unlink_internal(vfs_handle_struct *handle,
656 				struct files_struct *dirfsp,
657 				const struct smb_filename *smb_fname,
658 				int flags)
659 {
660 	struct smb_filename *smb_fname_base = NULL;
661 	int ret = -1;
662 
663 	DEBUG(10, ("streams_depot_unlink called for %s\n",
664 		   smb_fname_str_dbg(smb_fname)));
665 
666 	/* If there is a valid stream, just unlink the stream and return. */
667 	if (is_named_stream(smb_fname)) {
668 		struct smb_filename *smb_fname_stream = NULL;
669 		NTSTATUS status;
670 
671 		status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
672 					  false);
673 		if (!NT_STATUS_IS_OK(status)) {
674 			errno = map_errno_from_nt_status(status);
675 			return -1;
676 		}
677 
678 		ret = SMB_VFS_NEXT_UNLINKAT(handle,
679 				dirfsp,
680 				smb_fname_stream,
681 				0);
682 
683 		TALLOC_FREE(smb_fname_stream);
684 		return ret;
685 	}
686 
687 	/*
688 	 * We potentially need to delete the per-inode streams directory
689 	 */
690 
691 	smb_fname_base = synthetic_smb_fname(talloc_tos(),
692 					smb_fname->base_name,
693 					NULL,
694 					NULL,
695 					smb_fname->flags);
696 	if (smb_fname_base == NULL) {
697 		errno = ENOMEM;
698 		return -1;
699 	}
700 
701 	if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
702 		ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
703 	} else {
704 		ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
705 	}
706 
707 	if (ret == -1) {
708 		TALLOC_FREE(smb_fname_base);
709 		return -1;
710 	}
711 
712 	/*
713 	 * We know the unlink should succeed as the ACL
714 	 * check is already done in the caller. Remove the
715 	 * file *after* the streams.
716 	 */
717 	{
718 		char *dirname = stream_dir(handle, smb_fname_base,
719 					   &smb_fname_base->st, false);
720 
721 		if (dirname != NULL) {
722 			struct smb_filename *smb_fname_dir =
723 				synthetic_smb_fname(talloc_tos(),
724 						dirname,
725 						NULL,
726 						NULL,
727 						smb_fname->flags);
728 			if (smb_fname_dir == NULL) {
729 				TALLOC_FREE(smb_fname_base);
730 				TALLOC_FREE(dirname);
731 				errno = ENOMEM;
732 				return -1;
733 			}
734 			SMB_VFS_NEXT_UNLINKAT(handle,
735 				dirfsp,
736 				smb_fname_dir,
737 				AT_REMOVEDIR);
738 			TALLOC_FREE(smb_fname_dir);
739 		}
740 		TALLOC_FREE(dirname);
741 	}
742 
743 	ret = SMB_VFS_NEXT_UNLINKAT(handle,
744 				dirfsp,
745 				smb_fname,
746 				flags);
747 	TALLOC_FREE(smb_fname_base);
748 	return ret;
749 }
750 
streams_depot_rmdir_internal(vfs_handle_struct * handle,struct files_struct * dirfsp,const struct smb_filename * smb_fname)751 static int streams_depot_rmdir_internal(vfs_handle_struct *handle,
752 			struct files_struct *dirfsp,
753 			const struct smb_filename *smb_fname)
754 {
755 	struct smb_filename *smb_fname_base = NULL;
756 	int ret = -1;
757 
758 	DBG_DEBUG("called for %s\n", smb_fname->base_name);
759 
760 	/*
761 	 * We potentially need to delete the per-inode streams directory
762 	 */
763 
764 	smb_fname_base = synthetic_smb_fname(talloc_tos(),
765 				smb_fname->base_name,
766 				NULL,
767 				NULL,
768 				smb_fname->flags);
769 	if (smb_fname_base == NULL) {
770 		errno = ENOMEM;
771 		return -1;
772 	}
773 
774 	if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
775 		ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
776 	} else {
777 		ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
778 	}
779 
780 	if (ret == -1) {
781 		TALLOC_FREE(smb_fname_base);
782 		return -1;
783 	}
784 
785 	/*
786 	 * We know the rmdir should succeed as the ACL
787 	 * check is already done in the caller. Remove the
788 	 * directory *after* the streams.
789 	 */
790 	{
791 		char *dirname = stream_dir(handle, smb_fname_base,
792 					   &smb_fname_base->st, false);
793 
794 		if (dirname != NULL) {
795 			struct smb_filename *smb_fname_dir =
796 				synthetic_smb_fname(talloc_tos(),
797 						dirname,
798 						NULL,
799 						NULL,
800 						smb_fname->flags);
801 			if (smb_fname_dir == NULL) {
802 				TALLOC_FREE(smb_fname_base);
803 				TALLOC_FREE(dirname);
804 				errno = ENOMEM;
805 				return -1;
806 			}
807 			SMB_VFS_NEXT_UNLINKAT(handle,
808 					dirfsp,
809 					smb_fname_dir,
810 					AT_REMOVEDIR);
811 			TALLOC_FREE(smb_fname_dir);
812 		}
813 		TALLOC_FREE(dirname);
814 	}
815 
816 	ret = SMB_VFS_NEXT_UNLINKAT(handle,
817 				dirfsp,
818 				smb_fname_base,
819 				AT_REMOVEDIR);
820 	TALLOC_FREE(smb_fname_base);
821 	return ret;
822 }
823 
streams_depot_unlinkat(vfs_handle_struct * handle,struct files_struct * dirfsp,const struct smb_filename * smb_fname,int flags)824 static int streams_depot_unlinkat(vfs_handle_struct *handle,
825 			struct files_struct *dirfsp,
826 			const struct smb_filename *smb_fname,
827 			int flags)
828 {
829 	int ret;
830 	SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
831 	if (flags & AT_REMOVEDIR) {
832 		ret = streams_depot_rmdir_internal(handle,
833 				dirfsp,
834 				smb_fname);
835 	} else {
836 		ret = streams_depot_unlink_internal(handle,
837 				dirfsp,
838 				smb_fname,
839 				flags);
840 	}
841 	return ret;
842 }
843 
streams_depot_renameat(vfs_handle_struct * handle,files_struct * srcfsp,const struct smb_filename * smb_fname_src,files_struct * dstfsp,const struct smb_filename * smb_fname_dst)844 static int streams_depot_renameat(vfs_handle_struct *handle,
845 				files_struct *srcfsp,
846 				const struct smb_filename *smb_fname_src,
847 				files_struct *dstfsp,
848 				const struct smb_filename *smb_fname_dst)
849 {
850 	struct smb_filename *smb_fname_src_stream = NULL;
851 	struct smb_filename *smb_fname_dst_stream = NULL;
852 	bool src_is_stream, dst_is_stream;
853 	NTSTATUS status;
854 	int ret = -1;
855 
856 	DEBUG(10, ("streams_depot_renameat called for %s => %s\n",
857 		   smb_fname_str_dbg(smb_fname_src),
858 		   smb_fname_str_dbg(smb_fname_dst)));
859 
860 	src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
861 	dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
862 
863 	if (!src_is_stream && !dst_is_stream) {
864 		return SMB_VFS_NEXT_RENAMEAT(handle,
865 					srcfsp,
866 					smb_fname_src,
867 					dstfsp,
868 					smb_fname_dst);
869 	}
870 
871 	/* for now don't allow renames from or to the default stream */
872 	if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
873 	    is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
874 		errno = ENOSYS;
875 		goto done;
876 	}
877 
878 	status = stream_smb_fname(handle, smb_fname_src, &smb_fname_src_stream,
879 				  false);
880 	if (!NT_STATUS_IS_OK(status)) {
881 		errno = map_errno_from_nt_status(status);
882 		goto done;
883 	}
884 
885 	status = stream_smb_fname(handle, smb_fname_dst,
886 				  &smb_fname_dst_stream, false);
887 	if (!NT_STATUS_IS_OK(status)) {
888 		errno = map_errno_from_nt_status(status);
889 		goto done;
890 	}
891 
892 	ret = SMB_VFS_NEXT_RENAMEAT(handle,
893 				srcfsp,
894 				smb_fname_src_stream,
895 				dstfsp,
896 				smb_fname_dst_stream);
897 
898 done:
899 	TALLOC_FREE(smb_fname_src_stream);
900 	TALLOC_FREE(smb_fname_dst_stream);
901 	return ret;
902 }
903 
add_one_stream(TALLOC_CTX * mem_ctx,unsigned int * num_streams,struct stream_struct ** streams,const char * name,off_t size,off_t alloc_size)904 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
905 			   struct stream_struct **streams,
906 			   const char *name, off_t size,
907 			   off_t alloc_size)
908 {
909 	struct stream_struct *tmp;
910 
911 	tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
912 				   (*num_streams)+1);
913 	if (tmp == NULL) {
914 		return false;
915 	}
916 
917 	tmp[*num_streams].name = talloc_strdup(tmp, name);
918 	if (tmp[*num_streams].name == NULL) {
919 		return false;
920 	}
921 
922 	tmp[*num_streams].size = size;
923 	tmp[*num_streams].alloc_size = alloc_size;
924 
925 	*streams = tmp;
926 	*num_streams += 1;
927 	return true;
928 }
929 
930 struct streaminfo_state {
931 	TALLOC_CTX *mem_ctx;
932 	vfs_handle_struct *handle;
933 	unsigned int num_streams;
934 	struct stream_struct *streams;
935 	NTSTATUS status;
936 };
937 
collect_one_stream(const char * dirname,const char * dirent,void * private_data)938 static bool collect_one_stream(const char *dirname,
939 			       const char *dirent,
940 			       void *private_data)
941 {
942 	struct streaminfo_state *state =
943 		(struct streaminfo_state *)private_data;
944 	struct smb_filename *smb_fname = NULL;
945 	char *sname = NULL;
946 	bool ret;
947 
948 	sname = talloc_asprintf(talloc_tos(), "%s/%s", dirname, dirent);
949 	if (sname == NULL) {
950 		state->status = NT_STATUS_NO_MEMORY;
951 		ret = false;
952 		goto out;
953 	}
954 
955 	smb_fname = synthetic_smb_fname(talloc_tos(), sname, NULL, NULL, 0);
956 	if (smb_fname == NULL) {
957 		state->status = NT_STATUS_NO_MEMORY;
958 		ret = false;
959 		goto out;
960 	}
961 
962 	if (SMB_VFS_NEXT_STAT(state->handle, smb_fname) == -1) {
963 		DEBUG(10, ("Could not stat %s: %s\n", sname,
964 			   strerror(errno)));
965 		ret = true;
966 		goto out;
967 	}
968 
969 	if (!add_one_stream(state->mem_ctx,
970 			    &state->num_streams, &state->streams,
971 			    dirent, smb_fname->st.st_ex_size,
972 			    SMB_VFS_GET_ALLOC_SIZE(state->handle->conn, NULL,
973 						   &smb_fname->st))) {
974 		state->status = NT_STATUS_NO_MEMORY;
975 		ret = false;
976 		goto out;
977 	}
978 
979 	ret = true;
980  out:
981 	TALLOC_FREE(sname);
982 	TALLOC_FREE(smb_fname);
983 	return ret;
984 }
985 
streams_depot_streaminfo(vfs_handle_struct * handle,struct files_struct * fsp,const struct smb_filename * smb_fname,TALLOC_CTX * mem_ctx,unsigned int * pnum_streams,struct stream_struct ** pstreams)986 static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
987 					 struct files_struct *fsp,
988 					 const struct smb_filename *smb_fname,
989 					 TALLOC_CTX *mem_ctx,
990 					 unsigned int *pnum_streams,
991 					 struct stream_struct **pstreams)
992 {
993 	struct smb_filename *smb_fname_base = NULL;
994 	int ret;
995 	NTSTATUS status;
996 	struct streaminfo_state state;
997 
998 	smb_fname_base = synthetic_smb_fname(talloc_tos(),
999 					smb_fname->base_name,
1000 					NULL,
1001 					NULL,
1002 					smb_fname->flags);
1003 	if (smb_fname_base == NULL) {
1004 		return NT_STATUS_NO_MEMORY;
1005 	}
1006 
1007 	if ((fsp != NULL) && (fsp->fh->fd != -1)) {
1008 		ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st);
1009 	}
1010 	else {
1011 		if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
1012 			ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
1013 		} else {
1014 			ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
1015 		}
1016 	}
1017 
1018 	if (ret == -1) {
1019 		status = map_nt_error_from_unix(errno);
1020 		goto out;
1021 	}
1022 
1023 	state.streams = *pstreams;
1024 	state.num_streams = *pnum_streams;
1025 	state.mem_ctx = mem_ctx;
1026 	state.handle = handle;
1027 	state.status = NT_STATUS_OK;
1028 
1029 	if (S_ISLNK(smb_fname_base->st.st_ex_mode)) {
1030 		/*
1031 		 * Currently we do't have SMB_VFS_LLISTXATTR
1032 		 * inside the VFS which means there's no way
1033 		 * to cope with a symlink when lp_posix_pathnames().
1034 		 * returns true. For now ignore links.
1035 		 * FIXME - by adding SMB_VFS_LLISTXATTR. JRA.
1036 		 */
1037 		status = NT_STATUS_OK;
1038 	} else {
1039 		status = walk_streams(handle, smb_fname_base, NULL, collect_one_stream,
1040 			      &state);
1041 	}
1042 
1043 	if (!NT_STATUS_IS_OK(status)) {
1044 		TALLOC_FREE(state.streams);
1045 		goto out;
1046 	}
1047 
1048 	if (!NT_STATUS_IS_OK(state.status)) {
1049 		TALLOC_FREE(state.streams);
1050 		status = state.status;
1051 		goto out;
1052 	}
1053 
1054 	*pnum_streams = state.num_streams;
1055 	*pstreams = state.streams;
1056 	status = SMB_VFS_NEXT_STREAMINFO(handle,
1057 				fsp,
1058 				smb_fname_base,
1059 				mem_ctx,
1060 				pnum_streams,
1061 				pstreams);
1062 
1063  out:
1064 	TALLOC_FREE(smb_fname_base);
1065 	return status;
1066 }
1067 
streams_depot_fs_capabilities(struct vfs_handle_struct * handle,enum timestamp_set_resolution * p_ts_res)1068 static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle,
1069 			enum timestamp_set_resolution *p_ts_res)
1070 {
1071 	return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS;
1072 }
1073 
1074 static struct vfs_fn_pointers vfs_streams_depot_fns = {
1075 	.fs_capabilities_fn = streams_depot_fs_capabilities,
1076 	.open_fn = streams_depot_open,
1077 	.stat_fn = streams_depot_stat,
1078 	.lstat_fn = streams_depot_lstat,
1079 	.unlinkat_fn = streams_depot_unlinkat,
1080 	.renameat_fn = streams_depot_renameat,
1081 	.streaminfo_fn = streams_depot_streaminfo,
1082 };
1083 
1084 static_decl_vfs;
vfs_streams_depot_init(TALLOC_CTX * ctx)1085 NTSTATUS vfs_streams_depot_init(TALLOC_CTX *ctx)
1086 {
1087 	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
1088 				&vfs_streams_depot_fns);
1089 }
1090