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