Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/smbd/filename.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   filename handling routines
4
   Copyright (C) Andrew Tridgell 1992-1998
5
   Copyright (C) Jeremy Allison 1999-2007
6
   Copyright (C) Ying Chen 2000
7
   Copyright (C) Volker Lendecke 2007
8
9
   This program is free software; you can redistribute it and/or modify
10
   it under the terms of the GNU General Public License as published by
11
   the Free Software Foundation; either version 3 of the License, or
12
   (at your option) any later version.
13
14
   This program is distributed in the hope that it will be useful,
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
19
   You should have received a copy of the GNU General Public License
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
*/
22
23
/*
24
 * New hash table stat cache code added by Ying Chen.
25
 */
26
27
#include "includes.h"
28
#include "system/filesys.h"
29
#include "fake_file.h"
30
#include "smbd/smbd.h"
31
#include "smbd/globals.h"
32
#include "libcli/smb/reparse.h"
33
#include "source3/smbd/dir.h"
34
35
uint32_t ucf_flags_from_smb_request(struct smb_request *req)
36
0
{
37
0
  uint32_t ucf_flags = 0;
38
39
0
  if (req == NULL) {
40
0
    return 0;
41
0
  }
42
43
0
  if (req->posix_pathnames) {
44
0
    ucf_flags |= (UCF_POSIX_PATHNAMES|UCF_LCOMP_LNK_OK);
45
0
  }
46
0
  if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
47
0
    ucf_flags |= UCF_DFS_PATHNAME;
48
0
  }
49
0
  if (req->flags2 & FLAGS2_REPARSE_PATH) {
50
0
    ucf_flags |= UCF_GMT_PATHNAME;
51
0
  }
52
53
0
  return ucf_flags;
54
0
}
55
56
uint32_t filename_create_ucf_flags(struct smb_request *req,
57
           uint32_t create_disposition,
58
           uint32_t create_options)
59
0
{
60
0
  uint32_t ucf_flags = 0;
61
62
0
  ucf_flags |= ucf_flags_from_smb_request(req);
63
64
0
  switch (create_disposition) {
65
0
  case FILE_OPEN:
66
0
  case FILE_OVERWRITE:
67
0
    break;
68
0
  case FILE_SUPERSEDE:
69
0
  case FILE_CREATE:
70
0
  case FILE_OPEN_IF:
71
0
  case FILE_OVERWRITE_IF:
72
0
    ucf_flags |= UCF_PREP_CREATEFILE;
73
0
    break;
74
0
  }
75
76
0
  if (create_options & FILE_OPEN_REPARSE_POINT) {
77
0
    ucf_flags |= UCF_LCOMP_LNK_OK;
78
0
  }
79
80
0
  return ucf_flags;
81
0
}
82
83
/****************************************************************************
84
 Mangle the 2nd name and check if it is then equal to the first name.
85
****************************************************************************/
86
87
static bool mangled_equal(const char *name1,
88
      const char *name2,
89
      const struct share_params *p)
90
0
{
91
0
  char mname[13];
92
93
0
  if (!name_to_8_3(name2, mname, False, p)) {
94
0
    return False;
95
0
  }
96
0
  return strequal(name1, mname);
97
0
}
98
99
/*
100
 * Strip a valid @GMT-token from any incoming filename path,
101
 * adding any NTTIME encoded in the pathname into the
102
 * twrp field of the passed in smb_fname.
103
 *
104
 * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
105
 * at the *start* of a pathname component.
106
 *
107
 * If twrp is passed in then smb_fname->twrp is set to that
108
 * value, and the @GMT-token part of the filename is removed
109
 * and does not change the stored smb_fname->twrp.
110
 *
111
 */
112
113
NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname,
114
            uint32_t ucf_flags,
115
            NTTIME twrp)
116
0
{
117
0
  bool found;
118
119
0
  if (twrp != 0) {
120
0
    smb_fname->twrp = twrp;
121
0
  }
122
123
0
  if (!(ucf_flags & UCF_GMT_PATHNAME)) {
124
0
    return NT_STATUS_OK;
125
0
  }
126
127
0
  found = extract_snapshot_token(smb_fname->base_name, &twrp);
128
0
  if (!found) {
129
0
    return NT_STATUS_OK;
130
0
  }
131
132
0
  if (smb_fname->twrp == 0) {
133
0
    smb_fname->twrp = twrp;
134
0
  }
135
136
0
  return NT_STATUS_OK;
137
0
}
138
139
static bool strnorm(char *s, int case_default)
140
0
{
141
0
  if (case_default == CASE_UPPER)
142
0
    return strupper_m(s);
143
0
  else
144
0
    return strlower_m(s);
145
0
}
146
147
/*
148
 * Utility function to normalize case on an incoming client filename
149
 * if required on this connection struct.
150
 * Performs an in-place case conversion guaranteed to stay the same size.
151
 */
152
153
static NTSTATUS normalize_filename_case(connection_struct *conn,
154
          char *filename,
155
          uint32_t ucf_flags)
156
0
{
157
0
  bool ok;
158
159
0
  if (ucf_flags & UCF_POSIX_PATHNAMES) {
160
    /*
161
     * POSIX never normalizes filename case.
162
     */
163
0
    return NT_STATUS_OK;
164
0
  }
165
0
  if (!conn->case_sensitive) {
166
0
    return NT_STATUS_OK;
167
0
  }
168
0
  if (conn->case_preserve) {
169
0
    return NT_STATUS_OK;
170
0
  }
171
0
  if (conn->short_case_preserve) {
172
0
    return NT_STATUS_OK;
173
0
  }
174
0
  ok = strnorm(filename, lp_default_case(SNUM(conn)));
175
0
  if (!ok) {
176
0
    return NT_STATUS_INVALID_PARAMETER;
177
0
  }
178
0
  return NT_STATUS_OK;
179
0
}
180
181
/****************************************************************************
182
 Check if two filenames are equal.
183
 This needs to be careful about whether we are case sensitive.
184
****************************************************************************/
185
186
static bool fname_equal(const char *name1, const char *name2,
187
    bool case_sensitive)
188
0
{
189
  /* Normal filename handling */
190
0
  if (case_sensitive) {
191
0
    return(strcmp(name1,name2) == 0);
192
0
  }
193
194
0
  return(strequal(name1,name2));
195
0
}
196
197
static bool sname_equal(const char *name1, const char *name2,
198
    bool case_sensitive)
199
0
{
200
0
  bool match;
201
0
  const char *s1 = NULL;
202
0
  const char *s2 = NULL;
203
0
  size_t n1;
204
0
  size_t n2;
205
0
  const char *e1 = NULL;
206
0
  const char *e2 = NULL;
207
0
  char *c1 = NULL;
208
0
  char *c2 = NULL;
209
210
0
  match = fname_equal(name1, name2, case_sensitive);
211
0
  if (match) {
212
0
    return true;
213
0
  }
214
215
0
  if (name1[0] != ':') {
216
0
    return false;
217
0
  }
218
0
  if (name2[0] != ':') {
219
0
    return false;
220
0
  }
221
0
  s1 = &name1[1];
222
0
  e1 = strchr(s1, ':');
223
0
  if (e1 == NULL) {
224
0
    n1 = strlen(s1);
225
0
  } else {
226
0
    n1 = PTR_DIFF(e1, s1);
227
0
  }
228
0
  s2 = &name2[1];
229
0
  e2 = strchr(s2, ':');
230
0
  if (e2 == NULL) {
231
0
    n2 = strlen(s2);
232
0
  } else {
233
0
    n2 = PTR_DIFF(e2, s2);
234
0
  }
235
236
  /* Normal filename handling */
237
0
  if (case_sensitive) {
238
0
    return (strncmp(s1, s2, n1) == 0);
239
0
  }
240
241
  /*
242
   * We can't use strnequal() here
243
   * as it takes the number of codepoints
244
   * and not the number of bytes.
245
   *
246
   * So we make a copy before calling
247
   * strequal().
248
   *
249
   * Note that we TALLOC_FREE() in reverse order
250
   * in order to avoid memory fragmentation.
251
   */
252
253
0
  c1 = talloc_strndup(talloc_tos(), s1, n1);
254
0
  c2 = talloc_strndup(talloc_tos(), s2, n2);
255
0
  if (c1 == NULL || c2 == NULL) {
256
0
    TALLOC_FREE(c2);
257
0
    TALLOC_FREE(c1);
258
0
    return (strncmp(s1, s2, n1) == 0);
259
0
  }
260
261
0
  match = strequal(c1, c2);
262
0
  TALLOC_FREE(c2);
263
0
  TALLOC_FREE(c1);
264
0
  return match;
265
0
}
266
267
/****************************************************************************
268
 Scan a directory to find a filename, matching without case sensitivity.
269
 If the name looks like a mangled name then try via the mangling functions
270
****************************************************************************/
271
272
static NTSTATUS get_real_filename_full_scan_at(struct files_struct *dirfsp,
273
                 const char *name,
274
                 bool mangled,
275
                 TALLOC_CTX *mem_ctx,
276
                 char **found_name)
277
0
{
278
0
  struct connection_struct *conn = dirfsp->conn;
279
0
  struct smb_Dir *cur_dir = NULL;
280
0
  const char *dname = NULL;
281
0
  char *talloced = NULL;
282
0
  char *unmangled_name = NULL;
283
0
  NTSTATUS status;
284
285
  /* If we have a case-sensitive filesystem, it doesn't do us any
286
   * good to search for a name. If a case variation of the name was
287
   * there, then the original stat(2) would have found it.
288
   */
289
0
  if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
290
0
    return NT_STATUS_OBJECT_NAME_NOT_FOUND;
291
0
  }
292
293
  /*
294
   * The incoming name can be mangled, and if we de-mangle it
295
   * here it will not compare correctly against the filename (name2)
296
   * read from the directory and then mangled by the name_to_8_3()
297
   * call. We need to mangle both names or neither.
298
   * (JRA).
299
   *
300
   * Fix for bug found by Dina Fine. If in case sensitive mode then
301
   * the mangle cache is no good (3 letter extension could be wrong
302
   * case - so don't demangle in this case - leave as mangled and
303
   * allow the mangling of the directory entry read (which is done
304
   * case insensitively) to match instead. This will lead to more
305
   * false positive matches but we fail completely without it. JRA.
306
   */
307
308
0
  if (mangled && !conn->case_sensitive) {
309
0
    mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
310
0
                   &unmangled_name,
311
0
                   conn->params);
312
0
    if (!mangled) {
313
      /* Name is now unmangled. */
314
0
      name = unmangled_name;
315
0
    }
316
0
  }
317
318
  /* open the directory */
319
0
  status = OpenDir_from_pathref(talloc_tos(), dirfsp, NULL, 0, &cur_dir);
320
0
  if (!NT_STATUS_IS_OK(status)) {
321
0
    DBG_NOTICE("scan dir didn't open dir [%s]: %s\n",
322
0
         fsp_str_dbg(dirfsp),
323
0
         nt_errstr(status));
324
0
    TALLOC_FREE(unmangled_name);
325
0
    return status;
326
0
  }
327
328
  /* now scan for matching names */
329
0
  while ((dname = ReadDirName(cur_dir, &talloced))) {
330
331
0
    if (ISDOT(dname) || ISDOTDOT(dname)) {
332
0
      TALLOC_FREE(talloced);
333
0
      continue;
334
0
    }
335
336
    /*
337
     * At this point dname is the unmangled name.
338
     * name is either mangled or not, depending on the state
339
     * of the "mangled" variable. JRA.
340
     */
341
342
    /*
343
     * Check mangled name against mangled name, or unmangled name
344
     * against unmangled name.
345
     */
346
347
0
    if ((mangled && mangled_equal(name,dname,conn->params)) ||
348
0
      fname_equal(name, dname, conn->case_sensitive)) {
349
      /* we've found the file, change it's name and return */
350
0
      *found_name = talloc_strdup(mem_ctx, dname);
351
0
      TALLOC_FREE(unmangled_name);
352
0
      TALLOC_FREE(cur_dir);
353
0
      if (!*found_name) {
354
0
        TALLOC_FREE(talloced);
355
0
        return NT_STATUS_NO_MEMORY;
356
0
      }
357
0
      TALLOC_FREE(talloced);
358
0
      return NT_STATUS_OK;
359
0
    }
360
0
    TALLOC_FREE(talloced);
361
0
  }
362
363
0
  TALLOC_FREE(unmangled_name);
364
0
  TALLOC_FREE(cur_dir);
365
0
  return NT_STATUS_OBJECT_NAME_NOT_FOUND;
366
0
}
367
368
/****************************************************************************
369
 Wrapper around the vfs get_real_filename and the full directory scan
370
 fallback.
371
****************************************************************************/
372
373
NTSTATUS get_real_filename_at(struct files_struct *dirfsp,
374
            const char *name,
375
            TALLOC_CTX *mem_ctx,
376
            char **found_name)
377
0
{
378
0
  struct connection_struct *conn = dirfsp->conn;
379
0
  NTSTATUS status;
380
0
  bool mangled;
381
382
0
  mangled = mangle_is_mangled(name, conn->params);
383
384
0
  if (mangled) {
385
0
    status = get_real_filename_full_scan_at(
386
0
      dirfsp, name, mangled, mem_ctx, found_name);
387
0
    return status;
388
0
  }
389
390
  /* Try the vfs first to take advantage of case-insensitive stat. */
391
0
  status = SMB_VFS_GET_REAL_FILENAME_AT(
392
0
    dirfsp->conn, dirfsp, name, mem_ctx, found_name);
393
394
  /*
395
   * If the case-insensitive stat was successful, or returned an error
396
   * other than EOPNOTSUPP then there is no need to fall back on the
397
   * full directory scan.
398
   */
399
0
  if (NT_STATUS_IS_OK(status) ||
400
0
      !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
401
0
    return status;
402
0
  }
403
404
0
  status = get_real_filename_full_scan_at(
405
0
    dirfsp, name, mangled, mem_ctx, found_name);
406
0
  return status;
407
0
}
408
409
/*
410
 * Lightweight function to just get last component
411
 * for rename / enumerate directory calls.
412
 */
413
414
char *get_original_lcomp(TALLOC_CTX *ctx,
415
      connection_struct *conn,
416
      const char *filename_in,
417
      uint32_t ucf_flags)
418
0
{
419
0
  char *last_slash = NULL;
420
0
  char *orig_lcomp;
421
0
  NTSTATUS status;
422
423
0
  last_slash = strrchr(filename_in, '/');
424
0
  if (last_slash != NULL) {
425
0
    orig_lcomp = talloc_strdup(ctx, last_slash+1);
426
0
  } else {
427
0
    orig_lcomp = talloc_strdup(ctx, filename_in);
428
0
  }
429
0
  if (orig_lcomp == NULL) {
430
0
    return NULL;
431
0
  }
432
0
  status = normalize_filename_case(conn, orig_lcomp, ucf_flags);
433
0
  if (!NT_STATUS_IS_OK(status)) {
434
0
    TALLOC_FREE(orig_lcomp);
435
0
    return NULL;
436
0
  }
437
0
  return orig_lcomp;
438
0
}
439
440
/*
441
 * Get the correct capitalized stream name hanging off
442
 * base_fsp. Equivalent of get_real_filename(), but for streams.
443
 */
444
static NTSTATUS get_real_stream_name(
445
  TALLOC_CTX *mem_ctx,
446
  struct files_struct *base_fsp,
447
  const char *stream_name,
448
  char **_found)
449
0
{
450
0
  unsigned int i, num_streams = 0;
451
0
  struct stream_struct *streams = NULL;
452
0
  NTSTATUS status;
453
454
0
  status = vfs_fstreaminfo(
455
0
    base_fsp, talloc_tos(), &num_streams, &streams);
456
0
  if (!NT_STATUS_IS_OK(status)) {
457
0
    return status;
458
0
  }
459
460
0
  for (i=0; i<num_streams; i++) {
461
0
    bool equal = sname_equal(stream_name, streams[i].name, false);
462
463
0
    DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
464
0
        stream_name,
465
0
        streams[i].name,
466
0
        equal ? "" : "not ");
467
468
0
    if (equal) {
469
0
      *_found = talloc_move(mem_ctx, &streams[i].name);
470
0
      TALLOC_FREE(streams);
471
0
      return NT_STATUS_OK;
472
0
    }
473
0
  }
474
475
0
  TALLOC_FREE(streams);
476
0
  return NT_STATUS_OBJECT_NAME_NOT_FOUND;
477
0
}
478
479
static bool filename_split_lcomp(
480
  TALLOC_CTX *mem_ctx,
481
  const char *name_in,
482
  bool posix,
483
  char **_dirname,
484
  const char **_fname_rel,
485
  const char **_streamname)
486
0
{
487
0
  const char *lcomp = NULL;
488
0
  const char *fname_rel = NULL;
489
0
  const char *streamname = NULL;
490
0
  char *dirname = NULL;
491
492
0
  if (name_in[0] == '\0') {
493
0
    fname_rel = ".";
494
0
    dirname = talloc_strdup(mem_ctx, "");
495
0
    if (dirname == NULL) {
496
0
      return false;
497
0
    }
498
0
    goto done;
499
0
  }
500
501
0
  lcomp = strrchr_m(name_in, '/');
502
0
  if (lcomp != NULL) {
503
0
    fname_rel = lcomp+1;
504
0
    dirname = talloc_strndup(mem_ctx, name_in, lcomp - name_in);
505
0
    if (dirname == NULL) {
506
0
      return false;
507
0
    }
508
0
    goto find_stream;
509
0
  }
510
511
  /*
512
   * No slash, dir is empty
513
   */
514
0
  dirname = talloc_strdup(mem_ctx, "");
515
0
  if (dirname == NULL) {
516
0
    return false;
517
0
  }
518
519
0
  if (!posix && (name_in[0] == ':')) {
520
    /*
521
     * Special case for stream on root directory
522
     */
523
0
    fname_rel = ".";
524
0
    streamname = name_in;
525
0
    goto done;
526
0
  }
527
528
0
  fname_rel = name_in;
529
530
0
find_stream:
531
0
  if (!posix) {
532
0
    streamname = strchr_m(fname_rel, ':');
533
534
0
    if (streamname != NULL) {
535
0
      fname_rel = talloc_strndup(
536
0
        mem_ctx,
537
0
        fname_rel,
538
0
        streamname - fname_rel);
539
0
      if (fname_rel == NULL) {
540
0
        TALLOC_FREE(dirname);
541
0
        return false;
542
0
      }
543
0
    }
544
0
  }
545
546
0
done:
547
0
  *_dirname = dirname;
548
0
  *_fname_rel = fname_rel;
549
0
  *_streamname = streamname;
550
0
  return true;
551
0
}
552
553
/*
554
 * Create the correct capitalization of a file name to be created.
555
 */
556
static NTSTATUS filename_convert_normalize_new(
557
  TALLOC_CTX *mem_ctx,
558
  struct connection_struct *conn,
559
  char *name_in,
560
  char **_normalized)
561
0
{
562
0
  char *name = name_in;
563
564
0
  *_normalized = NULL;
565
566
0
  if (!conn->case_preserve ||
567
0
      (mangle_is_8_3(name, false,
568
0
         conn->params) &&
569
0
       !conn->short_case_preserve)) {
570
571
0
    char *normalized = talloc_strdup(mem_ctx, name);
572
0
    if (normalized == NULL) {
573
0
      return NT_STATUS_NO_MEMORY;
574
0
    }
575
576
0
    strnorm(normalized, lp_default_case(SNUM(conn)));
577
0
    name = normalized;
578
0
  }
579
580
0
  if (mangle_is_mangled(name, conn->params)) {
581
0
    bool found;
582
0
    char *unmangled = NULL;
583
584
0
    found = mangle_lookup_name_from_8_3(
585
0
      mem_ctx, name, &unmangled, conn->params);
586
0
    if (found) {
587
0
      name = unmangled;
588
0
    }
589
0
  }
590
591
0
  if (name != name_in) {
592
0
    *_normalized = name;
593
0
  }
594
595
0
  return NT_STATUS_OK;
596
0
}
597
598
static NTSTATUS safe_symlink_target_path(TALLOC_CTX *mem_ctx,
599
           const char *connectpath,
600
           const char *dir,
601
           const char *target,
602
           size_t unparsed,
603
           char **_relative)
604
0
{
605
0
  char *abs_target = NULL;
606
0
  char *abs_target_canon = NULL;
607
0
  const char *relative = NULL;
608
0
  bool in_share;
609
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
610
611
0
  DBG_DEBUG("connectpath [%s] target [%s] unparsed [%zu]\n",
612
0
      connectpath, target, unparsed);
613
614
0
  if (target[0] == '/') {
615
0
    abs_target = talloc_strdup(mem_ctx, target);
616
0
  } else if (dir == NULL) {
617
0
    abs_target = talloc_asprintf(mem_ctx,
618
0
               "%s/%s",
619
0
               connectpath,
620
0
               target);
621
0
  } else if (dir[0] == '/') {
622
0
    abs_target = talloc_asprintf(mem_ctx,
623
0
               "%s/%s",
624
0
               dir,
625
0
               target);
626
0
  } else {
627
0
    abs_target = talloc_asprintf(mem_ctx,
628
0
               "%s/%s/%s",
629
0
               connectpath,
630
0
               dir,
631
0
               target);
632
0
  }
633
0
  if (abs_target == NULL) {
634
0
    goto fail;
635
0
  }
636
637
0
  abs_target_canon = canonicalize_absolute_path(abs_target, abs_target);
638
0
  if (abs_target_canon == NULL) {
639
0
    goto fail;
640
0
  }
641
642
0
  DBG_DEBUG("abs_target_canon=%s\n", abs_target_canon);
643
644
0
  in_share = subdir_of(
645
0
    connectpath, strlen(connectpath), abs_target_canon, &relative);
646
0
  if (!in_share) {
647
0
    DBG_DEBUG("wide link to %s\n", abs_target_canon);
648
0
    status = (unparsed != 0) ? NT_STATUS_OBJECT_PATH_NOT_FOUND
649
0
           : NT_STATUS_OBJECT_NAME_NOT_FOUND;
650
0
    goto fail;
651
0
  }
652
653
0
  *_relative = talloc_strdup(mem_ctx, relative);
654
0
  if (*_relative == NULL) {
655
0
    goto fail;
656
0
  }
657
658
0
  status = NT_STATUS_OK;
659
0
fail:
660
0
  TALLOC_FREE(abs_target);
661
0
  return status;
662
0
}
663
664
/*
665
 * Split up name_in as sent by the client into a directory pathref fsp
666
 * and a relative smb_filename.
667
 */
668
NTSTATUS
669
filename_convert_dirfsp_nosymlink(TALLOC_CTX *mem_ctx,
670
          connection_struct *conn,
671
          struct files_struct *basedir,
672
          const char *name_in,
673
          uint32_t ucf_flags,
674
          NTTIME twrp,
675
          struct files_struct **_dirfsp,
676
          struct smb_filename **_smb_fname,
677
          struct smb_filename **_smb_fname_rel,
678
          struct reparse_data_buffer **_symlink_err)
679
0
{
680
0
  struct smb_filename *smb_dirname = NULL;
681
0
  struct smb_filename *smb_fname_rel = NULL;
682
0
  struct smb_filename *smb_fname = NULL;
683
0
  struct reparse_data_buffer *symlink_err = NULL;
684
0
  const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
685
0
  char *dirname = NULL;
686
0
  const char *fname_rel = NULL;
687
0
  const char *streamname = NULL;
688
0
  char *saved_streamname = NULL;
689
0
  struct files_struct *base_fsp = NULL;
690
0
  bool ok;
691
0
  NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
692
693
0
  SMB_ASSERT(!(ucf_flags & UCF_DFS_PATHNAME));
694
695
0
  if (is_fake_file_path(name_in)) {
696
0
    const struct timespec omit = make_omit_timespec();
697
698
0
    if (posix) {
699
      /*
700
       * No stream name to look for
701
       */
702
0
      smb_fname = synthetic_smb_fname(
703
0
        mem_ctx,
704
0
        name_in,
705
0
        NULL,
706
0
        NULL,
707
0
        0,
708
0
        SMB_FILENAME_POSIX_PATH);
709
0
    } else {
710
0
      smb_fname = synthetic_smb_fname_split(mem_ctx, name_in);
711
0
    }
712
0
    if (smb_fname == NULL) {
713
0
      return NT_STATUS_NO_MEMORY;
714
0
    }
715
0
    smb_fname->st = (SMB_STRUCT_STAT){
716
0
      .st_ex_nlink = 1,
717
0
      .st_ex_mode = S_IFREG | 0644,
718
0
      .st_ex_btime = omit,
719
0
      .st_ex_atime = omit,
720
0
      .st_ex_mtime = omit,
721
0
      .st_ex_ctime = omit,
722
0
    };
723
724
0
    *_dirfsp = basedir;
725
0
    *_smb_fname = smb_fname;
726
0
    return NT_STATUS_OK;
727
0
  }
728
729
  /*
730
   * Catch an invalid path of "." before we
731
   * call filename_split_lcomp(). We need to
732
   * do this as filename_split_lcomp() will
733
   * use "." for the missing relative component
734
   * when an empty name_in path is sent by
735
   * the client.
736
   */
737
0
  if (ISDOT(name_in)) {
738
0
    status = NT_STATUS_OBJECT_NAME_INVALID;
739
0
    goto fail;
740
0
  }
741
742
0
  ok = filename_split_lcomp(
743
0
    talloc_tos(),
744
0
    name_in,
745
0
    posix,
746
0
    &dirname,
747
0
    &fname_rel,
748
0
    &streamname);
749
0
  if (!ok) {
750
0
    status = NT_STATUS_NO_MEMORY;
751
0
    goto fail;
752
0
  }
753
754
0
  if ((streamname != NULL) &&
755
0
      ((conn->fs_capabilities & FILE_NAMED_STREAMS) == 0)) {
756
0
    status = NT_STATUS_OBJECT_NAME_INVALID;
757
0
    goto fail;
758
0
  }
759
760
0
  if (!posix) {
761
0
    bool name_has_wild = ms_has_wild(dirname);
762
0
    name_has_wild |= ms_has_wild(fname_rel);
763
0
    if (name_has_wild) {
764
0
      status = NT_STATUS_OBJECT_NAME_INVALID;
765
0
      goto fail;
766
0
    }
767
0
  }
768
769
0
  if (dirname[0] == '\0') {
770
0
    status = openat_pathref_fsp_dot(
771
0
      mem_ctx, basedir,
772
0
      posix ? SMB_FILENAME_POSIX_PATH : 0, &smb_dirname);
773
0
  } else {
774
0
    status = normalize_filename_case(conn, dirname, ucf_flags);
775
0
    if (!NT_STATUS_IS_OK(status)) {
776
0
      DBG_ERR("normalize_filename_case %s failed: %s\n",
777
0
        dirname,
778
0
        nt_errstr(status));
779
0
      goto fail;
780
0
    }
781
782
0
    status = openat_pathref_fsp_nosymlink(mem_ctx,
783
0
                  conn,
784
0
                  basedir,
785
0
                  dirname,
786
0
                  twrp,
787
0
                  posix,
788
0
                  &smb_dirname,
789
0
                  &symlink_err);
790
791
0
    if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
792
0
      struct symlink_reparse_struct
793
0
        *lnk = &symlink_err->parsed.lnk;
794
0
      size_t unparsed = lnk->unparsed_path_length;
795
0
      size_t name_in_len, dirname_len;
796
797
0
      name_in_len = strlen(name_in);
798
0
      dirname_len = strlen(dirname);
799
800
0
      SMB_ASSERT(name_in_len >= dirname_len);
801
802
0
      unparsed += (name_in_len - dirname_len);
803
804
0
      if (unparsed > UINT16_MAX) {
805
0
        status = NT_STATUS_BUFFER_OVERFLOW;
806
0
        goto fail;
807
0
      }
808
809
0
      lnk->unparsed_path_length = unparsed;
810
0
      goto fail;
811
0
    }
812
0
  }
813
814
0
  if (!NT_STATUS_IS_OK(status)) {
815
0
    DBG_DEBUG("opening directory %s failed: %s\n",
816
0
        dirname,
817
0
        nt_errstr(status));
818
0
    TALLOC_FREE(dirname);
819
820
0
    if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
821
      /*
822
       * Except ACCESS_DENIED, everything else leads
823
       * to PATH_NOT_FOUND.
824
       */
825
0
      status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
826
0
    }
827
828
0
    goto fail;
829
0
  }
830
831
0
  if (!VALID_STAT_OF_DIR(smb_dirname->st)) {
832
0
    status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
833
0
    goto fail;
834
0
  }
835
0
  smb_dirname->fsp->fsp_flags.is_directory = true;
836
837
  /*
838
   * Only look at bad last component values
839
   * once we know we have a valid directory. That
840
   * way we won't confuse error messages from
841
   * opening the directory path with error
842
   * messages from a bad last component.
843
   */
844
845
  /* Relative filename can't be empty */
846
0
  if (fname_rel[0] == '\0') {
847
0
    status = NT_STATUS_OBJECT_NAME_INVALID;
848
0
    goto fail;
849
0
  }
850
851
  /* Relative filename can't be ".." */
852
0
  if (ISDOTDOT(fname_rel)) {
853
0
    status = NT_STATUS_OBJECT_NAME_INVALID;
854
0
    goto fail;
855
0
  }
856
  /* Relative name can only be dot if directory is empty. */
857
0
  if (ISDOT(fname_rel) && dirname[0] != '\0') {
858
0
    status = NT_STATUS_OBJECT_NAME_INVALID;
859
0
    goto fail;
860
0
  }
861
862
0
  TALLOC_FREE(dirname);
863
864
0
  smb_fname_rel = synthetic_smb_fname(
865
0
    mem_ctx,
866
0
    fname_rel,
867
0
    streamname,
868
0
    NULL,
869
0
    twrp,
870
0
    posix ? SMB_FILENAME_POSIX_PATH : 0);
871
0
  if (smb_fname_rel == NULL) {
872
0
    status = NT_STATUS_NO_MEMORY;
873
0
    goto fail;
874
0
  }
875
876
0
  if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
877
0
      is_named_stream(smb_fname_rel)) {
878
    /*
879
     * Find the base_fsp first without the stream.
880
     */
881
0
    saved_streamname = smb_fname_rel->stream_name;
882
0
    smb_fname_rel->stream_name = NULL;
883
0
  }
884
885
0
  status = normalize_filename_case(
886
0
    conn, smb_fname_rel->base_name, ucf_flags);
887
0
  if (!NT_STATUS_IS_OK(status)) {
888
0
    DBG_ERR("normalize_filename_case %s failed: %s\n",
889
0
      smb_fname_rel->base_name,
890
0
      nt_errstr(status));
891
0
    goto fail;
892
0
  }
893
894
0
  status = openat_pathref_fsp_lcomp(smb_dirname->fsp,
895
0
            smb_fname_rel,
896
0
            ucf_flags);
897
898
0
  if (NT_STATUS_IS_OK(status) && S_ISLNK(smb_fname_rel->st.st_ex_mode)) {
899
900
    /*
901
     * Upper layers might need the link target. Here we
902
     * still have the relname around, get the symlink err.
903
     */
904
0
    status = read_symlink_reparse(mem_ctx,
905
0
                smb_dirname->fsp,
906
0
                smb_fname_rel,
907
0
                &symlink_err);
908
0
    if (!NT_STATUS_IS_OK(status)) {
909
0
      DBG_DEBUG("Could not read symlink for %s: %s\n",
910
0
          smb_fname_str_dbg(
911
0
            smb_fname_rel->fsp->fsp_name),
912
0
          nt_errstr(status));
913
0
      goto fail;
914
0
    }
915
0
  }
916
917
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
918
0
      !VALID_STAT(smb_fname_rel->st)) {
919
920
0
    char *normalized = NULL;
921
922
    /*
923
     * Creating a new file
924
     */
925
926
0
    status = filename_convert_normalize_new(
927
0
      smb_fname_rel,
928
0
      conn,
929
0
      smb_fname_rel->base_name,
930
0
      &normalized);
931
0
    if (!NT_STATUS_IS_OK(status)) {
932
0
      DBG_DEBUG("filename_convert_normalize_new failed: "
933
0
          "%s\n",
934
0
          nt_errstr(status));
935
0
      goto fail;
936
0
    }
937
0
    if (normalized != NULL) {
938
0
      smb_fname_rel->base_name = normalized;
939
0
    }
940
941
0
    smb_fname_rel->stream_name = saved_streamname;
942
943
0
    smb_fname = full_path_from_dirfsp_atname(
944
0
      mem_ctx, smb_dirname->fsp, smb_fname_rel);
945
0
    if (smb_fname == NULL) {
946
0
      status = NT_STATUS_NO_MEMORY;
947
0
      goto fail;
948
0
    }
949
0
    goto done;
950
0
  }
951
952
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_OPEN_RESTRICTION)) {
953
    /* A vetoed file, pretend it's not there  */
954
0
    status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
955
0
  }
956
0
  if (!NT_STATUS_IS_OK(status)) {
957
0
    goto fail;
958
0
  }
959
960
0
  if (saved_streamname == NULL) {
961
    /* smb_fname must be allocated off mem_ctx. */
962
0
    smb_fname = cp_smb_filename(mem_ctx,
963
0
              smb_fname_rel->fsp->fsp_name);
964
0
    if (smb_fname == NULL) {
965
0
      goto fail;
966
0
    }
967
0
    status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
968
0
    if (!NT_STATUS_IS_OK(status)) {
969
0
      goto fail;
970
0
    }
971
0
    goto done;
972
0
  }
973
974
0
  base_fsp = smb_fname_rel->fsp;
975
0
  smb_fname_fsp_unlink(smb_fname_rel);
976
0
  SET_STAT_INVALID(smb_fname_rel->st);
977
978
0
  smb_fname_rel->stream_name = saved_streamname;
979
980
0
  status = open_stream_pathref_fsp(&base_fsp, smb_fname_rel);
981
982
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
983
0
      !conn->case_sensitive) {
984
0
    char *found = NULL;
985
986
0
    status = get_real_stream_name(
987
0
      smb_fname_rel,
988
0
      base_fsp,
989
0
      smb_fname_rel->stream_name,
990
0
      &found);
991
992
0
    if (NT_STATUS_IS_OK(status)) {
993
0
      smb_fname_rel->stream_name = found;
994
0
      found = NULL;
995
0
      status = open_stream_pathref_fsp(
996
0
        &base_fsp, smb_fname_rel);
997
0
    }
998
0
  }
999
1000
0
  if (NT_STATUS_IS_OK(status)) {
1001
    /* smb_fname must be allocated off mem_ctx. */
1002
0
    smb_fname = cp_smb_filename(mem_ctx,
1003
0
              smb_fname_rel->fsp->fsp_name);
1004
0
    if (smb_fname == NULL) {
1005
0
      goto fail;
1006
0
    }
1007
0
    status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1008
0
    if (!NT_STATUS_IS_OK(status)) {
1009
0
      goto fail;
1010
0
    }
1011
0
    goto done;
1012
0
  }
1013
1014
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1015
    /*
1016
     * Creating a new stream
1017
     *
1018
     * We should save the already-open base fsp for
1019
     * create_file_unixpath() somehow.
1020
     */
1021
0
    smb_fname = full_path_from_dirfsp_atname(
1022
0
      mem_ctx, smb_dirname->fsp, smb_fname_rel);
1023
0
    if (smb_fname == NULL) {
1024
0
      status = NT_STATUS_NO_MEMORY;
1025
0
      goto fail;
1026
0
    }
1027
    /*
1028
     * When open_stream_pathref_fsp() returns
1029
     * NT_STATUS_OBJECT_NAME_NOT_FOUND, smb_fname_rel->fsp
1030
     * has been set to NULL, so we must free base_fsp separately
1031
     * to prevent fd-leaks when opening a stream that doesn't
1032
     * exist.
1033
     */
1034
0
    fd_close(base_fsp);
1035
0
    file_free(NULL, base_fsp);
1036
0
    base_fsp = NULL;
1037
0
    goto done;
1038
0
  }
1039
1040
0
  if (!NT_STATUS_IS_OK(status)) {
1041
0
    goto fail;
1042
0
  }
1043
1044
0
done:
1045
0
  *_dirfsp = smb_dirname->fsp;
1046
0
  *_smb_fname = smb_fname;
1047
0
  *_symlink_err = symlink_err;
1048
1049
0
  smb_fname_fsp_unlink(smb_fname_rel);
1050
0
  *_smb_fname_rel = smb_fname_rel;
1051
0
  return NT_STATUS_OK;
1052
1053
0
fail:
1054
0
  *_symlink_err = symlink_err;
1055
1056
  /*
1057
   * If open_stream_pathref_fsp() returns an error, smb_fname_rel->fsp
1058
   * has been set to NULL, so we must free base_fsp separately
1059
   * to prevent fd-leaks when opening a stream that doesn't
1060
   * exist.
1061
   */
1062
0
  if (base_fsp != NULL) {
1063
0
    fd_close(base_fsp);
1064
0
    file_free(NULL, base_fsp);
1065
0
    base_fsp = NULL;
1066
0
  }
1067
0
  TALLOC_FREE(dirname);
1068
0
  TALLOC_FREE(smb_dirname);
1069
0
  TALLOC_FREE(smb_fname_rel);
1070
0
  return status;
1071
0
}
1072
1073
NTSTATUS filename_convert_dirfsp_rel(TALLOC_CTX *mem_ctx,
1074
             connection_struct *conn,
1075
             struct files_struct *basedir,
1076
             const char *name_in,
1077
             uint32_t ucf_flags,
1078
             NTTIME twrp,
1079
             struct files_struct **_dirfsp,
1080
             struct smb_filename **_smb_fname,
1081
             struct smb_filename **_smb_fname_rel)
1082
0
{
1083
0
  struct reparse_data_buffer *symlink_err = NULL;
1084
0
  struct symlink_reparse_struct *lnk = NULL;
1085
0
  NTSTATUS status;
1086
0
  char *target = NULL;
1087
0
  char *base_name = NULL;
1088
0
  char *safe_target = NULL;
1089
0
  size_t symlink_redirects = 0;
1090
0
  int ret;
1091
1092
0
next:
1093
0
  if (symlink_redirects > 40) {
1094
0
    return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1095
0
  }
1096
1097
0
  status = filename_convert_dirfsp_nosymlink(mem_ctx,
1098
0
               conn,
1099
0
               basedir,
1100
0
               name_in,
1101
0
               ucf_flags,
1102
0
               twrp,
1103
0
               _dirfsp,
1104
0
               _smb_fname,
1105
0
               _smb_fname_rel,
1106
0
               &symlink_err);
1107
1108
0
  if (NT_STATUS_IS_OK(status) && S_ISLNK((*_smb_fname)->st.st_ex_mode)) {
1109
    /*
1110
     * lcomp is a symlink
1111
     */
1112
0
    if (ucf_flags & UCF_LCOMP_LNK_OK) {
1113
0
      TALLOC_FREE(symlink_err);
1114
0
      return NT_STATUS_OK;
1115
0
    }
1116
0
    close_file_free(NULL, _dirfsp, ERROR_CLOSE);
1117
0
    status = NT_STATUS_STOPPED_ON_SYMLINK;
1118
0
  }
1119
1120
0
  if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1121
0
    return status;
1122
0
  }
1123
0
  TALLOC_FREE(*_smb_fname_rel);
1124
1125
0
  lnk = &symlink_err->parsed.lnk;
1126
1127
  /*
1128
   * If we're on an MSDFS share, see if this is
1129
   * an MSDFS link.
1130
   */
1131
0
  if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
1132
0
      strnequal(lnk->substitute_name, "msdfs:", 6))
1133
0
  {
1134
0
    TALLOC_FREE(*_smb_fname);
1135
0
    TALLOC_FREE(symlink_err);
1136
0
    return NT_STATUS_PATH_NOT_COVERED;
1137
0
  }
1138
1139
0
  if (!lp_follow_symlinks(SNUM(conn))) {
1140
0
    status = (lnk->unparsed_path_length == 0)
1141
0
         ? NT_STATUS_OBJECT_NAME_NOT_FOUND
1142
0
         : NT_STATUS_OBJECT_PATH_NOT_FOUND;
1143
0
    TALLOC_FREE(symlink_err);
1144
0
    return status;
1145
0
  }
1146
1147
  /*
1148
   * Right now, SMB2 and SMB1 always traverse symlinks
1149
   * within the share. SMB1+POSIX traverses non-terminal
1150
   * symlinks within the share.
1151
   *
1152
   * When we add SMB2+POSIX we need to return
1153
   * a NT_STATUS_STOPPED_ON_SYMLINK error here, using the
1154
   * symlink target data read below if SMB2+POSIX has
1155
   * UCF_POSIX_PATHNAMES set to cause the client to
1156
   * resolve all symlinks locally.
1157
   */
1158
1159
0
  ret = symlink_target_path(mem_ctx,
1160
0
          name_in,
1161
0
          lnk->unparsed_path_length,
1162
0
          lnk->substitute_name,
1163
0
          lnk->substitute_name[0] != '/',
1164
0
          '/',
1165
0
          &target);
1166
0
  if (ret != 0) {
1167
0
    TALLOC_FREE(symlink_err);
1168
0
    return map_nt_error_from_unix(ret);
1169
0
  }
1170
1171
0
  if (basedir != conn->cwd_fsp) {
1172
0
    base_name = basedir->fsp_name->base_name;
1173
0
  }
1174
1175
0
  status = safe_symlink_target_path(mem_ctx,
1176
0
            conn->connectpath,
1177
0
            base_name,
1178
0
            target,
1179
0
            lnk->unparsed_path_length,
1180
0
            &safe_target);
1181
0
  TALLOC_FREE(symlink_err);
1182
0
  if (!NT_STATUS_IS_OK(status)) {
1183
0
    return status;
1184
0
  }
1185
0
  name_in = safe_target;
1186
0
  basedir = conn->cwd_fsp;
1187
1188
0
  symlink_redirects += 1;
1189
1190
0
  goto next;
1191
0
}
1192
1193
NTSTATUS filename_convert_dirfsp(TALLOC_CTX *ctx,
1194
         connection_struct *conn,
1195
         const char *name_in,
1196
         uint32_t ucf_flags,
1197
         NTTIME twrp,
1198
         struct files_struct **_dirfsp,
1199
         struct smb_filename **_smb_name)
1200
0
{
1201
0
  struct smb_filename *smb_fname_rel = NULL;
1202
0
  NTSTATUS status;
1203
1204
0
  status = filename_convert_dirfsp_rel(ctx,
1205
0
               conn,
1206
0
               conn->cwd_fsp,
1207
0
               name_in,
1208
0
               ucf_flags,
1209
0
               twrp,
1210
0
               _dirfsp,
1211
0
               _smb_name,
1212
0
               &smb_fname_rel);
1213
0
  TALLOC_FREE(smb_fname_rel);
1214
0
  return status;
1215
0
}
1216
1217
char *full_path_from_dirfsp_at_basename(TALLOC_CTX *mem_ctx,
1218
          const struct files_struct *dirfsp,
1219
          const char *at_base_name)
1220
0
{
1221
0
  char *path = NULL;
1222
1223
0
  if (dirfsp == dirfsp->conn->cwd_fsp ||
1224
0
      ISDOT(dirfsp->fsp_name->base_name) || at_base_name[0] == '/') {
1225
0
    path = talloc_strdup(mem_ctx, at_base_name);
1226
0
  } else {
1227
0
    path = talloc_asprintf(mem_ctx,
1228
0
               "%s/%s",
1229
0
               dirfsp->fsp_name->base_name,
1230
0
               at_base_name);
1231
0
  }
1232
1233
0
  return path;
1234
0
}
1235
1236
/*
1237
 * Build the full path from a dirfsp and dirfsp relative name
1238
 */
1239
struct smb_filename *
1240
full_path_from_dirfsp_atname(TALLOC_CTX *mem_ctx,
1241
           const struct files_struct *dirfsp,
1242
           const struct smb_filename *atname)
1243
0
{
1244
0
  struct smb_filename *fname = NULL;
1245
0
  char *path = NULL;
1246
1247
0
  path = full_path_from_dirfsp_at_basename(mem_ctx,
1248
0
             dirfsp,
1249
0
             atname->base_name);
1250
0
  if (path == NULL) {
1251
0
    return NULL;
1252
0
  }
1253
1254
0
  fname = synthetic_smb_fname(mem_ctx,
1255
0
            path,
1256
0
            atname->stream_name,
1257
0
            &atname->st,
1258
0
            atname->twrp,
1259
0
            atname->flags);
1260
0
  TALLOC_FREE(path);
1261
0
  if (fname == NULL) {
1262
0
    return NULL;
1263
0
  }
1264
1265
0
  return fname;
1266
0
}