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