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