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