s3:libsmb: allow store_cldap_reply() to work with a ipv6 response
[samba.git] / source3 / modules / vfs_streams_depot.c
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 static uint32_t hash_fn(DATA_BLOB key)
41 {
42         uint32_t value; /* Used to compute the hash value.  */
43         uint32_t i;     /* Used to cycle through random values. */
44
45         /* Set the initial value from the key size. */
46         for (value = 0x238F13AF * key.length, i=0; i < key.length; i++)
47                 value = (value + (key.data[i] << (i*5 % 24)));
48
49         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 static bool file_is_valid(vfs_handle_struct *handle,
72                         const struct smb_filename *smb_fname)
73 {
74         char buf;
75         NTSTATUS status;
76         struct smb_filename *pathref = NULL;
77         int ret;
78
79         DEBUG(10, ("file_is_valid (%s) called\n", smb_fname->base_name));
80
81         status = synthetic_pathref(talloc_tos(),
82                                 handle->conn->cwd_fsp,
83                                 smb_fname->base_name,
84                                 NULL,
85                                 NULL,
86                                 smb_fname->twrp,
87                                 smb_fname->flags,
88                                 &pathref);
89         if (!NT_STATUS_IS_OK(status)) {
90                 return false;
91         }
92         ret = SMB_VFS_FGETXATTR(pathref->fsp,
93                                 SAMBA_XATTR_MARKER,
94                                 &buf,
95                                 sizeof(buf));
96         if (ret != sizeof(buf)) {
97                 int saved_errno = errno;
98                 DBG_DEBUG("FGETXATTR failed: %s\n", strerror(saved_errno));
99                 TALLOC_FREE(pathref);
100                 errno = saved_errno;
101                 return false;
102         }
103
104         TALLOC_FREE(pathref);
105
106         if (buf != '1') {
107                 DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
108                 return false;
109         }
110
111         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 static char *stream_rootdir(vfs_handle_struct *handle,
125                             TALLOC_CTX *ctx)
126 {
127         const struct loadparm_substitution *lp_sub =
128                 loadparm_s3_global_substitution();
129         char *tmp;
130
131         tmp = talloc_asprintf(ctx,
132                               "%s/.streams",
133                               handle->conn->connectpath);
134         if (tmp == NULL) {
135                 errno = ENOMEM;
136                 return NULL;
137         }
138
139         return lp_parm_substituted_string(ctx,
140                                           lp_sub,
141                                           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 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         uint32_t hash;
156         struct smb_filename *smb_fname_hash = NULL;
157         char *result = NULL;
158         SMB_STRUCT_STAT base_sbuf_tmp;
159         char *tmp = NULL;
160         uint8_t first, second;
161         char *id_hex;
162         struct file_id id;
163         uint8_t id_buf[16];
164         bool check_valid;
165         char *rootdir = NULL;
166         struct smb_filename *rootdir_fname = NULL;
167         struct smb_filename *tmp_fname = NULL;
168         int ret;
169
170         check_valid = lp_parm_bool(SNUM(handle->conn),
171                       "streams_depot", "check_valid", true);
172
173         rootdir = stream_rootdir(handle,
174                                  talloc_tos());
175         if (rootdir == NULL) {
176                 errno = ENOMEM;
177                 goto fail;
178         }
179
180         rootdir_fname = synthetic_smb_fname(talloc_tos(),
181                                         rootdir,
182                                         NULL,
183                                         NULL,
184                                         smb_fname->twrp,
185                                         smb_fname->flags);
186         if (rootdir_fname == NULL) {
187                 errno = ENOMEM;
188                 goto fail;
189         }
190
191         /* Stat the base file if it hasn't already been done. */
192         if (base_sbuf == NULL) {
193                 struct smb_filename *smb_fname_base;
194
195                 smb_fname_base = synthetic_smb_fname(
196                                         talloc_tos(),
197                                         smb_fname->base_name,
198                                         NULL,
199                                         NULL,
200                                         smb_fname->twrp,
201                                         smb_fname->flags);
202                 if (smb_fname_base == NULL) {
203                         errno = ENOMEM;
204                         goto fail;
205                 }
206                 if (SMB_VFS_NEXT_STAT(handle, smb_fname_base) == -1) {
207                         TALLOC_FREE(smb_fname_base);
208                         goto fail;
209                 }
210                 base_sbuf_tmp = smb_fname_base->st;
211                 TALLOC_FREE(smb_fname_base);
212         } else {
213                 base_sbuf_tmp = *base_sbuf;
214         }
215
216         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &base_sbuf_tmp);
217
218         push_file_id_16((char *)id_buf, &id);
219
220         hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
221
222         first = hash & 0xff;
223         second = (hash >> 8) & 0xff;
224
225         id_hex = hex_encode_talloc(talloc_tos(), id_buf, sizeof(id_buf));
226
227         if (id_hex == NULL) {
228                 errno = ENOMEM;
229                 goto fail;
230         }
231
232         result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
233                                  first, second, id_hex);
234
235         TALLOC_FREE(id_hex);
236
237         if (result == NULL) {
238                 errno = ENOMEM;
239                 return NULL;
240         }
241
242         smb_fname_hash = synthetic_smb_fname(talloc_tos(),
243                                         result,
244                                         NULL,
245                                         NULL,
246                                         smb_fname->twrp,
247                                         smb_fname->flags);
248         if (smb_fname_hash == NULL) {
249                 errno = ENOMEM;
250                 goto fail;
251         }
252
253         if (SMB_VFS_NEXT_STAT(handle, smb_fname_hash) == 0) {
254                 struct smb_filename *smb_fname_new = NULL;
255                 char *newname;
256                 bool delete_lost;
257
258                 if (!S_ISDIR(smb_fname_hash->st.st_ex_mode)) {
259                         errno = EINVAL;
260                         goto fail;
261                 }
262
263                 if (!check_valid ||
264                     file_is_valid(handle, smb_fname)) {
265                         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         again:
275                 delete_lost = lp_parm_bool(SNUM(handle->conn), "streams_depot",
276                                            "delete_lost", false);
277
278                 if (delete_lost) {
279                         DEBUG(3, ("Someone has recreated a file under an "
280                               "existing inode. Removing: %s\n",
281                               smb_fname_hash->base_name));
282                         recursive_rmdir(talloc_tos(), handle->conn,
283                                         smb_fname_hash);
284                         SMB_VFS_NEXT_UNLINKAT(handle,
285                                         handle->conn->cwd_fsp,
286                                         smb_fname_hash,
287                                         AT_REMOVEDIR);
288                 } else {
289                         newname = talloc_asprintf(talloc_tos(), "lost-%lu",
290                                                   random());
291                         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                         if (newname == NULL) {
296                                 errno = ENOMEM;
297                                 goto fail;
298                         }
299
300                         smb_fname_new = synthetic_smb_fname(
301                                                 talloc_tos(),
302                                                 newname,
303                                                 NULL,
304                                                 NULL,
305                                                 smb_fname->twrp,
306                                                 smb_fname->flags);
307                         TALLOC_FREE(newname);
308                         if (smb_fname_new == NULL) {
309                                 errno = ENOMEM;
310                                 goto fail;
311                         }
312
313                         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                                 TALLOC_FREE(smb_fname_new);
319                                 if ((errno == EEXIST) || (errno == ENOTEMPTY)) {
320                                         goto again;
321                                 }
322                                 goto fail;
323                         }
324
325                         TALLOC_FREE(smb_fname_new);
326                 }
327         }
328
329         if (!create_it) {
330                 errno = ENOENT;
331                 goto fail;
332         }
333
334         ret = SMB_VFS_NEXT_MKDIRAT(handle,
335                                 handle->conn->cwd_fsp,
336                                 rootdir_fname,
337                                 0755);
338         if ((ret != 0) && (errno != EEXIST)) {
339                 goto fail;
340         }
341
342         tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
343         if (tmp == NULL) {
344                 errno = ENOMEM;
345                 goto fail;
346         }
347
348         tmp_fname = synthetic_smb_fname(talloc_tos(),
349                                         tmp,
350                                         NULL,
351                                         NULL,
352                                         smb_fname->twrp,
353                                         smb_fname->flags);
354         if (tmp_fname == NULL) {
355                 errno = ENOMEM;
356                 goto fail;
357         }
358
359         ret = SMB_VFS_NEXT_MKDIRAT(handle,
360                                 handle->conn->cwd_fsp,
361                                 tmp_fname,
362                                 0755);
363         if ((ret != 0) && (errno != EEXIST)) {
364                 goto fail;
365         }
366
367         TALLOC_FREE(tmp);
368         TALLOC_FREE(tmp_fname);
369
370         tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
371                               second);
372         if (tmp == NULL) {
373                 errno = ENOMEM;
374                 goto fail;
375         }
376
377         tmp_fname = synthetic_smb_fname(talloc_tos(),
378                                         tmp,
379                                         NULL,
380                                         NULL,
381                                         smb_fname->twrp,
382                                         smb_fname->flags);
383         if (tmp_fname == NULL) {
384                 errno = ENOMEM;
385                 goto fail;
386         }
387
388         ret = SMB_VFS_NEXT_MKDIRAT(handle,
389                         handle->conn->cwd_fsp,
390                         tmp_fname,
391                         0755);
392         if ((ret != 0) && (errno != EEXIST)) {
393                 goto fail;
394         }
395
396         TALLOC_FREE(tmp);
397         TALLOC_FREE(tmp_fname);
398
399         /* smb_fname_hash is the struct smb_filename version of 'result' */
400         ret = SMB_VFS_NEXT_MKDIRAT(handle,
401                         handle->conn->cwd_fsp,
402                         smb_fname_hash,
403                         0755);
404         if ((ret != 0) && (errno != EEXIST)) {
405                 goto fail;
406         }
407
408         TALLOC_FREE(rootdir_fname);
409         TALLOC_FREE(rootdir);
410         TALLOC_FREE(tmp_fname);
411         TALLOC_FREE(smb_fname_hash);
412         return result;
413
414  fail:
415         TALLOC_FREE(rootdir_fname);
416         TALLOC_FREE(rootdir);
417         TALLOC_FREE(tmp_fname);
418         TALLOC_FREE(smb_fname_hash);
419         TALLOC_FREE(result);
420         return NULL;
421 }
422 /**
423  * Given a stream name, populate smb_fname_out with the actual location of the
424  * stream.
425  */
426 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         char *dirname, *stream_fname;
433         const char *stype;
434         NTSTATUS status;
435
436         *smb_fname_out = NULL;
437
438         stype = strchr_m(smb_fname->stream_name + 1, ':');
439
440         if (stype) {
441                 if (strcasecmp_m(stype, ":$DATA") != 0) {
442                         return NT_STATUS_INVALID_PARAMETER;
443                 }
444         }
445
446         dirname = stream_dir(handle, smb_fname, base_sbuf, create_dir);
447
448         if (dirname == NULL) {
449                 status = map_nt_error_from_unix(errno);
450                 goto fail;
451         }
452
453         stream_fname = talloc_asprintf(talloc_tos(), "%s/%s", dirname,
454                                        smb_fname->stream_name);
455
456         if (stream_fname == NULL) {
457                 status = NT_STATUS_NO_MEMORY;
458                 goto fail;
459         }
460
461         if (stype == NULL) {
462                 /* Append an explicit stream type if one wasn't specified. */
463                 stream_fname = talloc_asprintf(talloc_tos(), "%s:$DATA",
464                                                stream_fname);
465                 if (stream_fname == NULL) {
466                         status = NT_STATUS_NO_MEMORY;
467                         goto fail;
468                 }
469         } else {
470                 /* Normalize the stream type to uppercase. */
471                 if (!strupper_m(strrchr_m(stream_fname, ':') + 1)) {
472                         status = NT_STATUS_INVALID_PARAMETER;
473                         goto fail;
474                 }
475         }
476
477         DEBUG(10, ("stream filename = %s\n", stream_fname));
478
479         /* Create an smb_filename with stream_name == NULL. */
480         *smb_fname_out = synthetic_smb_fname(talloc_tos(),
481                                         stream_fname,
482                                         NULL,
483                                         NULL,
484                                         smb_fname->twrp,
485                                         smb_fname->flags);
486         if (*smb_fname_out == NULL) {
487                 return NT_STATUS_NO_MEMORY;
488         }
489
490         return NT_STATUS_OK;
491
492  fail:
493         DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
494         TALLOC_FREE(*smb_fname_out);
495         return status;
496 }
497
498 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         char *dirname;
507         char *rootdir = NULL;
508         char *orig_connectpath = NULL;
509         struct smb_filename *dir_smb_fname = NULL;
510         struct smb_Dir *dir_hnd = NULL;
511         const char *dname = NULL;
512         char *talloced = NULL;
513         NTSTATUS status;
514
515         dirname = stream_dir(handle, smb_fname_base, &smb_fname_base->st,
516                              false);
517
518         if (dirname == NULL) {
519                 if (errno == ENOENT) {
520                         /*
521                          * no stream around
522                          */
523                         return NT_STATUS_OK;
524                 }
525                 return map_nt_error_from_unix(errno);
526         }
527
528         DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
529
530         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         if (dir_smb_fname == NULL) {
537                 TALLOC_FREE(dirname);
538                 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         rootdir = stream_rootdir(handle, talloc_tos());
548         if (rootdir == NULL) {
549                 TALLOC_FREE(dir_smb_fname);
550                 TALLOC_FREE(dirname);
551                 return NT_STATUS_NO_MEMORY;
552         }
553
554         orig_connectpath = handle->conn->connectpath;
555         handle->conn->connectpath = rootdir;
556
557         status = OpenDir(
558                 talloc_tos(), handle->conn, dir_smb_fname, NULL, 0, &dir_hnd);
559         if (!NT_STATUS_IS_OK(status)) {
560                 handle->conn->connectpath = orig_connectpath;
561                 TALLOC_FREE(rootdir);
562                 TALLOC_FREE(dir_smb_fname);
563                 TALLOC_FREE(dirname);
564                 return status;
565         }
566
567         while ((dname = ReadDirName(dir_hnd, &talloced)) != NULL) {
568                 if (ISDOT(dname) || ISDOTDOT(dname)) {
569                         TALLOC_FREE(talloced);
570                         continue;
571                 }
572
573                 DBG_DEBUG("dirent=%s\n", dname);
574
575                 if (!fn(dir_smb_fname, dname, private_data)) {
576                         TALLOC_FREE(talloced);
577                         break;
578                 }
579                 TALLOC_FREE(talloced);
580         }
581
582         /* Restore the original connectpath. */
583         handle->conn->connectpath = orig_connectpath;
584         TALLOC_FREE(rootdir);
585         TALLOC_FREE(dir_smb_fname);
586         TALLOC_FREE(dir_hnd);
587
588         if (pdirname != NULL) {
589                 *pdirname = dirname;
590         }
591         else {
592                 TALLOC_FREE(dirname);
593         }
594
595         return NT_STATUS_OK;
596 }
597
598 static int streams_depot_stat(vfs_handle_struct *handle,
599                               struct smb_filename *smb_fname)
600 {
601         struct smb_filename *smb_fname_stream = NULL;
602         NTSTATUS status;
603         int ret = -1;
604
605         DEBUG(10, ("streams_depot_stat called for [%s]\n",
606                    smb_fname_str_dbg(smb_fname)));
607
608         if (!is_named_stream(smb_fname)) {
609                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
610         }
611
612         /* Stat the actual stream now. */
613         status = stream_smb_fname(
614                 handle, NULL, smb_fname, &smb_fname_stream, false);
615         if (!NT_STATUS_IS_OK(status)) {
616                 ret = -1;
617                 errno = map_errno_from_nt_status(status);
618                 goto done;
619         }
620
621         ret = SMB_VFS_NEXT_STAT(handle, smb_fname_stream);
622
623         /* Update the original smb_fname with the stat info. */
624         smb_fname->st = smb_fname_stream->st;
625  done:
626         TALLOC_FREE(smb_fname_stream);
627         return ret;
628 }
629
630
631
632 static int streams_depot_lstat(vfs_handle_struct *handle,
633                                struct smb_filename *smb_fname)
634 {
635         struct smb_filename *smb_fname_stream = NULL;
636         NTSTATUS status;
637         int ret = -1;
638
639         DEBUG(10, ("streams_depot_lstat called for [%s]\n",
640                    smb_fname_str_dbg(smb_fname)));
641
642         if (!is_named_stream(smb_fname)) {
643                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
644         }
645
646         /* Stat the actual stream now. */
647         status = stream_smb_fname(
648                 handle, NULL, smb_fname, &smb_fname_stream, false);
649         if (!NT_STATUS_IS_OK(status)) {
650                 ret = -1;
651                 errno = map_errno_from_nt_status(status);
652                 goto done;
653         }
654
655         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_stream);
656
657  done:
658         TALLOC_FREE(smb_fname_stream);
659         return ret;
660 }
661
662 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         struct smb_filename *smb_fname_stream = NULL;
669         struct files_struct *fspcwd = NULL;
670         NTSTATUS status;
671         bool create_it;
672         int ret = -1;
673
674         if (!is_named_stream(smb_fname)) {
675                 return SMB_VFS_NEXT_OPENAT(handle,
676                                            dirfsp,
677                                            smb_fname,
678                                            fsp,
679                                            how);
680         }
681
682         if (how->resolve != 0) {
683                 errno = ENOSYS;
684                 return -1;
685         }
686
687         SMB_ASSERT(fsp_is_alternate_stream(fsp));
688         SMB_ASSERT(dirfsp == NULL);
689         SMB_ASSERT(VALID_STAT(fsp->base_fsp->fsp_name->st));
690
691         create_it = (how->flags & O_CREAT);
692
693         /* Determine the stream name, and then open it. */
694         status = stream_smb_fname(
695                 handle,
696                 &fsp->base_fsp->fsp_name->st,
697                 fsp->fsp_name,
698                 &smb_fname_stream,
699                 create_it);
700         if (!NT_STATUS_IS_OK(status)) {
701                 ret = -1;
702                 errno = map_errno_from_nt_status(status);
703                 goto done;
704         }
705
706         if (create_it) {
707                 bool check_valid = lp_parm_bool(
708                         SNUM(handle->conn),
709                         "streams_depot",
710                         "check_valid",
711                         true);
712
713                 if (check_valid) {
714                         char buf = '1';
715
716                         DBG_DEBUG("marking file %s as valid\n",
717                                   fsp->base_fsp->fsp_name->base_name);
718
719                         ret = SMB_VFS_FSETXATTR(
720                                 fsp->base_fsp,
721                                 SAMBA_XATTR_MARKER,
722                                 &buf,
723                                 sizeof(buf),
724                                 0);
725
726                         if (ret == -1) {
727                                 DBG_DEBUG("FSETXATTR failed: %s\n",
728                                           strerror(errno));
729                                 goto done;
730                         }
731                 }
732         }
733
734         status = vfs_at_fspcwd(talloc_tos(), handle->conn, &fspcwd);
735         if (!NT_STATUS_IS_OK(status)) {
736                 ret = -1;
737                 errno = map_errno_from_nt_status(status);
738                 goto done;
739         }
740
741         ret = SMB_VFS_NEXT_OPENAT(handle,
742                                   fspcwd,
743                                   smb_fname_stream,
744                                   fsp,
745                                   how);
746
747  done:
748         TALLOC_FREE(smb_fname_stream);
749         TALLOC_FREE(fspcwd);
750         return ret;
751 }
752
753 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         struct smb_filename *full_fname = NULL;
759         char *dirname = NULL;
760         int ret = -1;
761
762         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
763                                                   dirfsp,
764                                                   smb_fname);
765         if (full_fname == NULL) {
766                 return -1;
767         }
768
769         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         if (is_named_stream(full_fname)) {
774                 struct smb_filename *smb_fname_stream = NULL;
775                 NTSTATUS status;
776
777                 status = stream_smb_fname(
778                         handle, NULL, full_fname, &smb_fname_stream, false);
779                 TALLOC_FREE(full_fname);
780                 if (!NT_STATUS_IS_OK(status)) {
781                         errno = map_errno_from_nt_status(status);
782                         return -1;
783                 }
784
785                 ret = SMB_VFS_NEXT_UNLINKAT(handle,
786                                 dirfsp->conn->cwd_fsp,
787                                 smb_fname_stream,
788                                 0);
789
790                 TALLOC_FREE(smb_fname_stream);
791                 return ret;
792         }
793
794         /*
795          * We potentially need to delete the per-inode streams directory
796          */
797
798         if (full_fname->flags & SMB_FILENAME_POSIX_PATH) {
799                 ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
800         } else {
801                 ret = SMB_VFS_NEXT_STAT(handle, full_fname);
802                 if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
803                         if (VALID_STAT(smb_fname->st) &&
804                                         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                                 ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
810                         }
811                 }
812         }
813         if (ret == -1) {
814                 TALLOC_FREE(full_fname);
815                 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         dirname = stream_dir(handle,
824                              full_fname,
825                              &full_fname->st,
826                              false);
827         TALLOC_FREE(full_fname);
828         if (dirname != NULL) {
829                 struct smb_filename *smb_fname_dir = NULL;
830
831                 smb_fname_dir = synthetic_smb_fname(talloc_tos(),
832                                                     dirname,
833                                                     NULL,
834                                                     NULL,
835                                                     smb_fname->twrp,
836                                                     smb_fname->flags);
837                 if (smb_fname_dir == NULL) {
838                         TALLOC_FREE(dirname);
839                         errno = ENOMEM;
840                         return -1;
841                 }
842
843                 SMB_VFS_NEXT_UNLINKAT(handle,
844                                       dirfsp->conn->cwd_fsp,
845                                       smb_fname_dir,
846                                       AT_REMOVEDIR);
847                 TALLOC_FREE(smb_fname_dir);
848                 TALLOC_FREE(dirname);
849         }
850
851         ret = SMB_VFS_NEXT_UNLINKAT(handle,
852                                 dirfsp,
853                                 smb_fname,
854                                 flags);
855         return ret;
856 }
857
858 static int streams_depot_rmdir_internal(vfs_handle_struct *handle,
859                         struct files_struct *dirfsp,
860                         const struct smb_filename *smb_fname)
861 {
862         struct smb_filename *full_fname = NULL;
863         struct smb_filename *smb_fname_base = NULL;
864         int ret = -1;
865
866         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
867                                                   dirfsp,
868                                                   smb_fname);
869         if (full_fname == NULL) {
870                 return -1;
871         }
872
873         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         smb_fname_base = synthetic_smb_fname(talloc_tos(),
880                                 full_fname->base_name,
881                                 NULL,
882                                 NULL,
883                                 full_fname->twrp,
884                                 full_fname->flags);
885         TALLOC_FREE(full_fname);
886         if (smb_fname_base == NULL) {
887                 errno = ENOMEM;
888                 return -1;
889         }
890
891         if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
892                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
893         } else {
894                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
895         }
896
897         if (ret == -1) {
898                 TALLOC_FREE(smb_fname_base);
899                 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                 char *dirname = stream_dir(handle, smb_fname_base,
909                                            &smb_fname_base->st, false);
910
911                 if (dirname != NULL) {
912                         struct smb_filename *smb_fname_dir =
913                                 synthetic_smb_fname(talloc_tos(),
914                                                 dirname,
915                                                 NULL,
916                                                 NULL,
917                                                 smb_fname->twrp,
918                                                 smb_fname->flags);
919                         if (smb_fname_dir == NULL) {
920                                 TALLOC_FREE(smb_fname_base);
921                                 TALLOC_FREE(dirname);
922                                 errno = ENOMEM;
923                                 return -1;
924                         }
925                         SMB_VFS_NEXT_UNLINKAT(handle,
926                                         dirfsp->conn->cwd_fsp,
927                                         smb_fname_dir,
928                                         AT_REMOVEDIR);
929                         TALLOC_FREE(smb_fname_dir);
930                 }
931                 TALLOC_FREE(dirname);
932         }
933
934         ret = SMB_VFS_NEXT_UNLINKAT(handle,
935                                 dirfsp,
936                                 smb_fname,
937                                 AT_REMOVEDIR);
938         TALLOC_FREE(smb_fname_base);
939         return ret;
940 }
941
942 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         int ret;
948         if (flags & AT_REMOVEDIR) {
949                 ret = streams_depot_rmdir_internal(handle,
950                                 dirfsp,
951                                 smb_fname);
952         } else {
953                 ret = streams_depot_unlink_internal(handle,
954                                 dirfsp,
955                                 smb_fname,
956                                 flags);
957         }
958         return ret;
959 }
960
961 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         struct smb_filename *smb_fname_src_stream = NULL;
968         struct smb_filename *smb_fname_dst_stream = NULL;
969         struct smb_filename *full_src = NULL;
970         struct smb_filename *full_dst = NULL;
971         bool src_is_stream, dst_is_stream;
972         NTSTATUS status;
973         int ret = -1;
974
975         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         src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
980         dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
981
982         if (!src_is_stream && !dst_is_stream) {
983                 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         if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
992             is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
993                 errno = ENOSYS;
994                 goto done;
995         }
996
997         full_src = full_path_from_dirfsp_atname(talloc_tos(),
998                                                 srcfsp,
999                                                 smb_fname_src);
1000         if (full_src == NULL) {
1001                 errno = ENOMEM;
1002                 goto done;
1003         }
1004
1005         full_dst = full_path_from_dirfsp_atname(talloc_tos(),
1006                                                 dstfsp,
1007                                                 smb_fname_dst);
1008         if (full_dst == NULL) {
1009                 errno = ENOMEM;
1010                 goto done;
1011         }
1012
1013         status = stream_smb_fname(
1014                 handle, NULL, full_src, &smb_fname_src_stream, false);
1015         if (!NT_STATUS_IS_OK(status)) {
1016                 errno = map_errno_from_nt_status(status);
1017                 goto done;
1018         }
1019
1020         status = stream_smb_fname(
1021                 handle, NULL, full_dst, &smb_fname_dst_stream, false);
1022         if (!NT_STATUS_IS_OK(status)) {
1023                 errno = map_errno_from_nt_status(status);
1024                 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         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 done:
1041         TALLOC_FREE(smb_fname_src_stream);
1042         TALLOC_FREE(smb_fname_dst_stream);
1043         return ret;
1044 }
1045
1046 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         struct stream_struct *tmp;
1052
1053         tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
1054                                    (*num_streams)+1);
1055         if (tmp == NULL) {
1056                 return false;
1057         }
1058
1059         tmp[*num_streams].name = talloc_strdup(tmp, name);
1060         if (tmp[*num_streams].name == NULL) {
1061                 return false;
1062         }
1063
1064         tmp[*num_streams].size = size;
1065         tmp[*num_streams].alloc_size = alloc_size;
1066
1067         *streams = tmp;
1068         *num_streams += 1;
1069         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 static bool collect_one_stream(const struct smb_filename *dirfname,
1081                                const char *dirent,
1082                                void *private_data)
1083 {
1084         const char *dirname = dirfname->base_name;
1085         struct streaminfo_state *state =
1086                 (struct streaminfo_state *)private_data;
1087         struct smb_filename *smb_fname = NULL;
1088         char *sname = NULL;
1089         bool ret;
1090
1091         sname = talloc_asprintf(talloc_tos(), "%s/%s", dirname, dirent);
1092         if (sname == NULL) {
1093                 state->status = NT_STATUS_NO_MEMORY;
1094                 ret = false;
1095                 goto out;
1096         }
1097
1098         smb_fname = synthetic_smb_fname(talloc_tos(),
1099                                         sname,
1100                                         NULL,
1101                                         NULL,
1102                                         dirfname->twrp,
1103                                         0);
1104         if (smb_fname == NULL) {
1105                 state->status = NT_STATUS_NO_MEMORY;
1106                 ret = false;
1107                 goto out;
1108         }
1109
1110         if (SMB_VFS_NEXT_STAT(state->handle, smb_fname) == -1) {
1111                 DEBUG(10, ("Could not stat %s: %s\n", sname,
1112                            strerror(errno)));
1113                 ret = true;
1114                 goto out;
1115         }
1116
1117         if (!add_one_stream(state->mem_ctx,
1118                             &state->num_streams, &state->streams,
1119                             dirent, smb_fname->st.st_ex_size,
1120                             SMB_VFS_GET_ALLOC_SIZE(state->handle->conn, NULL,
1121                                                    &smb_fname->st))) {
1122                 state->status = NT_STATUS_NO_MEMORY;
1123                 ret = false;
1124                 goto out;
1125         }
1126
1127         ret = true;
1128  out:
1129         TALLOC_FREE(sname);
1130         TALLOC_FREE(smb_fname);
1131         return ret;
1132 }
1133
1134 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         struct smb_filename *smb_fname_base = NULL;
1141         int ret;
1142         NTSTATUS status;
1143         struct streaminfo_state state;
1144
1145         smb_fname_base = synthetic_smb_fname(talloc_tos(),
1146                                         fsp->fsp_name->base_name,
1147                                         NULL,
1148                                         NULL,
1149                                         fsp->fsp_name->twrp,
1150                                         fsp->fsp_name->flags);
1151         if (smb_fname_base == NULL) {
1152                 return NT_STATUS_NO_MEMORY;
1153         }
1154
1155         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st);
1156         if (ret == -1) {
1157                 status = map_nt_error_from_unix(errno);
1158                 goto out;
1159         }
1160
1161         state.streams = *pstreams;
1162         state.num_streams = *pnum_streams;
1163         state.mem_ctx = mem_ctx;
1164         state.handle = handle;
1165         state.status = NT_STATUS_OK;
1166
1167         status = walk_streams(handle,
1168                                 smb_fname_base,
1169                                 NULL,
1170                                 collect_one_stream,
1171                                 &state);
1172
1173         if (!NT_STATUS_IS_OK(status)) {
1174                 TALLOC_FREE(state.streams);
1175                 goto out;
1176         }
1177
1178         if (!NT_STATUS_IS_OK(state.status)) {
1179                 TALLOC_FREE(state.streams);
1180                 status = state.status;
1181                 goto out;
1182         }
1183
1184         *pnum_streams = state.num_streams;
1185         *pstreams = state.streams;
1186         status = SMB_VFS_NEXT_FSTREAMINFO(handle,
1187                                 fsp->base_fsp ? fsp->base_fsp : fsp,
1188                                 mem_ctx,
1189                                 pnum_streams,
1190                                 pstreams);
1191
1192  out:
1193         TALLOC_FREE(smb_fname_base);
1194         return status;
1195 }
1196
1197 static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle,
1198                         enum timestamp_set_resolution *p_ts_res)
1199 {
1200         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 NTSTATUS vfs_streams_depot_init(TALLOC_CTX *ctx)
1215 {
1216         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
1217                                 &vfs_streams_depot_fns);
1218 }