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 622872 : uint32_t ucf_flags_from_smb_request(struct smb_request *req)
36 : {
37 622872 : uint32_t ucf_flags = 0;
38 :
39 622872 : if (req == NULL) {
40 0 : return 0;
41 : }
42 :
43 622872 : if (req->posix_pathnames) {
44 4429 : ucf_flags |= UCF_POSIX_PATHNAMES;
45 :
46 4429 : if (!conn_using_smb2(req->sconn)) {
47 2285 : ucf_flags |= UCF_LCOMP_LNK_OK;
48 : }
49 : }
50 622872 : if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
51 1624 : ucf_flags |= UCF_DFS_PATHNAME;
52 : }
53 622872 : if (req->flags2 & FLAGS2_REPARSE_PATH) {
54 4178 : ucf_flags |= UCF_GMT_PATHNAME;
55 : }
56 :
57 612395 : return ucf_flags;
58 : }
59 :
60 515882 : uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
61 : {
62 515882 : uint32_t ucf_flags = 0;
63 :
64 515882 : ucf_flags |= ucf_flags_from_smb_request(req);
65 :
66 515882 : switch (create_disposition) {
67 333223 : case FILE_OPEN:
68 : case FILE_OVERWRITE:
69 333223 : break;
70 182027 : case FILE_SUPERSEDE:
71 : case FILE_CREATE:
72 : case FILE_OPEN_IF:
73 : case FILE_OVERWRITE_IF:
74 182027 : ucf_flags |= UCF_PREP_CREATEFILE;
75 182027 : break;
76 : }
77 :
78 515882 : 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 1227182 : static NTSTATUS normalize_filename_case(connection_struct *conn,
152 : char *filename,
153 : uint32_t ucf_flags)
154 : {
155 23613 : bool ok;
156 :
157 1227182 : if (ucf_flags & UCF_POSIX_PATHNAMES) {
158 : /*
159 : * POSIX never normalizes filename case.
160 : */
161 4955 : return NT_STATUS_OK;
162 : }
163 1222227 : if (!conn->case_sensitive) {
164 1219885 : 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 158832391 : static bool fname_equal(const char *name1, const char *name2,
185 : bool case_sensitive)
186 : {
187 : /* Normal filename handling */
188 158832391 : if (case_sensitive) {
189 0 : return(strcmp(name1,name2) == 0);
190 : }
191 :
192 158832391 : 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 273549 : 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 273549 : struct connection_struct *conn = dirfsp->conn;
277 273549 : struct smb_Dir *cur_dir = NULL;
278 273549 : const char *dname = NULL;
279 273549 : char *talloced = NULL;
280 273549 : 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 273549 : 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 273549 : if (mangled && !conn->case_sensitive) {
307 166 : mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
308 : &unmangled_name,
309 166 : conn->params);
310 166 : if (!mangled) {
311 : /* Name is now unmangled. */
312 142 : name = unmangled_name;
313 : }
314 : }
315 :
316 : /* open the directory */
317 273549 : status = OpenDir_from_pathref(talloc_tos(), dirfsp, NULL, 0, &cur_dir);
318 273549 : 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 159642877 : while ((dname = ReadDirName(cur_dir, &talloced))) {
328 :
329 : /* Is it dot or dot dot. */
330 159375549 : if (ISDOT(dname) || ISDOTDOT(dname)) {
331 547096 : TALLOC_FREE(talloced);
332 547096 : 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 317656882 : if ((mangled && mangled_equal(name,dname,conn->params)) ||
347 158828429 : fname_equal(name, dname, conn->case_sensitive)) {
348 : /* we've found the file, change it's name and return */
349 6220 : *found_name = talloc_strdup(mem_ctx, dname);
350 6220 : TALLOC_FREE(unmangled_name);
351 6220 : TALLOC_FREE(cur_dir);
352 6220 : if (!*found_name) {
353 0 : TALLOC_FREE(talloced);
354 0 : return NT_STATUS_NO_MEMORY;
355 : }
356 6220 : TALLOC_FREE(talloced);
357 6220 : return NT_STATUS_OK;
358 : }
359 158828902 : TALLOC_FREE(talloced);
360 : }
361 :
362 267328 : TALLOC_FREE(unmangled_name);
363 267328 : TALLOC_FREE(cur_dir);
364 267328 : 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 273549 : NTSTATUS get_real_filename_at(struct files_struct *dirfsp,
373 : const char *name,
374 : TALLOC_CTX *mem_ctx,
375 : char **found_name)
376 : {
377 273549 : struct connection_struct *conn = dirfsp->conn;
378 883 : NTSTATUS status;
379 883 : bool mangled;
380 :
381 273549 : mangled = mangle_is_mangled(name, conn->params);
382 :
383 273549 : if (mangled) {
384 166 : status = get_real_filename_full_scan_at(
385 : dirfsp, name, mangled, mem_ctx, found_name);
386 166 : return status;
387 : }
388 :
389 : /* Try the vfs first to take advantage of case-insensitive stat. */
390 273383 : 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 273383 : if (NT_STATUS_IS_OK(status) ||
399 272500 : !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
400 0 : return status;
401 : }
402 :
403 273383 : status = get_real_filename_full_scan_at(
404 : dirfsp, name, mangled, mem_ctx, found_name);
405 273383 : return status;
406 : }
407 :
408 : /*
409 : * Lightweight function to just get last component
410 : * for rename / enumerate directory calls.
411 : */
412 :
413 32492 : char *get_original_lcomp(TALLOC_CTX *ctx,
414 : connection_struct *conn,
415 : const char *filename_in,
416 : uint32_t ucf_flags)
417 : {
418 32492 : char *last_slash = NULL;
419 4300 : char *orig_lcomp;
420 4300 : NTSTATUS status;
421 :
422 32492 : last_slash = strrchr(filename_in, '/');
423 32492 : if (last_slash != NULL) {
424 28941 : orig_lcomp = talloc_strdup(ctx, last_slash+1);
425 : } else {
426 3551 : orig_lcomp = talloc_strdup(ctx, filename_in);
427 : }
428 32492 : if (orig_lcomp == NULL) {
429 0 : return NULL;
430 : }
431 32492 : status = normalize_filename_case(conn, orig_lcomp, ucf_flags);
432 32492 : if (!NT_STATUS_IS_OK(status)) {
433 0 : TALLOC_FREE(orig_lcomp);
434 0 : return NULL;
435 : }
436 28192 : 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 691333 : 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 691333 : const char *lcomp = NULL;
487 691333 : const char *fname_rel = NULL;
488 691333 : const char *streamname = NULL;
489 691333 : char *dirname = NULL;
490 :
491 691333 : if (name_in[0] == '\0') {
492 37267 : fname_rel = ".";
493 37267 : dirname = talloc_strdup(mem_ctx, "");
494 37267 : if (dirname == NULL) {
495 0 : return false;
496 : }
497 37267 : goto done;
498 : }
499 :
500 654066 : lcomp = strrchr_m(name_in, '/');
501 654066 : if (lcomp != NULL) {
502 575395 : fname_rel = lcomp+1;
503 575395 : dirname = talloc_strndup(mem_ctx, name_in, lcomp - name_in);
504 575395 : if (dirname == NULL) {
505 0 : return false;
506 : }
507 575395 : goto find_stream;
508 : }
509 :
510 : /*
511 : * No slash, dir is empty
512 : */
513 78671 : dirname = talloc_strdup(mem_ctx, "");
514 78671 : if (dirname == NULL) {
515 0 : return false;
516 : }
517 :
518 78671 : 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 77244 : fname_rel = name_in;
528 :
529 654034 : find_stream:
530 654034 : if (!posix) {
531 649651 : streamname = strchr_m(fname_rel, ':');
532 :
533 649651 : if (streamname != NULL) {
534 6401 : fname_rel = talloc_strndup(
535 : mem_ctx,
536 : fname_rel,
537 6400 : streamname - fname_rel);
538 6400 : if (fname_rel == NULL) {
539 0 : TALLOC_FREE(dirname);
540 0 : return false;
541 : }
542 : }
543 : }
544 :
545 654034 : done:
546 691333 : *_dirname = dirname;
547 691333 : *_fname_rel = fname_rel;
548 691333 : *_streamname = streamname;
549 691333 : return true;
550 : }
551 :
552 : /*
553 : * Create the correct capitalization of a file name to be created.
554 : */
555 268607 : 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 268607 : char *name = name_in;
562 :
563 268607 : *_normalized = NULL;
564 :
565 537210 : if (!conn->case_preserve ||
566 268603 : (mangle_is_8_3(name, false,
567 268603 : conn->params) &&
568 237482 : !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 268607 : if (mangle_is_mangled(name, conn->params)) {
580 0 : bool found;
581 52 : char *unmangled = NULL;
582 :
583 52 : found = mangle_lookup_name_from_8_3(
584 52 : mem_ctx, name, &unmangled, conn->params);
585 52 : if (found) {
586 44 : name = unmangled;
587 : }
588 : }
589 :
590 268607 : if (name != name_in) {
591 48 : *_normalized = name;
592 : }
593 :
594 268607 : 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 22809 : NTSTATUS safe_symlink_target_path(TALLOC_CTX *mem_ctx,
663 : const char *connectpath,
664 : const char *dir,
665 : const char *target,
666 : size_t unparsed,
667 : char **_relative)
668 : {
669 22809 : char *abs_target = NULL;
670 22809 : char *abs_target_canon = NULL;
671 22809 : const char *relative = NULL;
672 0 : bool in_share;
673 22809 : NTSTATUS status = NT_STATUS_NO_MEMORY;
674 :
675 22809 : DBG_DEBUG("connectpath [%s] target [%s] unparsed [%zu]\n",
676 : connectpath, target, unparsed);
677 :
678 22809 : if (target[0] == '/') {
679 13049 : abs_target = talloc_strdup(mem_ctx, target);
680 9760 : } else if (dir == NULL) {
681 9340 : abs_target = talloc_asprintf(mem_ctx,
682 : "%s/%s",
683 : connectpath,
684 : target);
685 420 : } else if (dir[0] == '/') {
686 20 : abs_target = talloc_asprintf(mem_ctx,
687 : "%s/%s",
688 : dir,
689 : target);
690 : } else {
691 400 : abs_target = talloc_asprintf(mem_ctx,
692 : "%s/%s/%s",
693 : connectpath,
694 : dir,
695 : target);
696 : }
697 22809 : if (abs_target == NULL) {
698 0 : goto fail;
699 : }
700 :
701 22809 : abs_target_canon = canonicalize_absolute_path(abs_target, abs_target);
702 22809 : if (abs_target_canon == NULL) {
703 0 : goto fail;
704 : }
705 :
706 22809 : DBG_DEBUG("abs_target_canon=%s\n", abs_target_canon);
707 :
708 22809 : in_share = subdir_of(
709 : connectpath, strlen(connectpath), abs_target_canon, &relative);
710 22809 : if (!in_share) {
711 2249 : DBG_DEBUG("wide link to %s\n", abs_target_canon);
712 2249 : status = (unparsed != 0) ? NT_STATUS_OBJECT_PATH_NOT_FOUND
713 4 : : NT_STATUS_OBJECT_NAME_NOT_FOUND;
714 2249 : goto fail;
715 : }
716 :
717 20560 : *_relative = talloc_strdup(mem_ctx, relative);
718 20560 : if (*_relative == NULL) {
719 0 : goto fail;
720 : }
721 :
722 20560 : status = NT_STATUS_OK;
723 22809 : fail:
724 22809 : TALLOC_FREE(abs_target);
725 22809 : return status;
726 : }
727 :
728 : /*
729 : * Split up name_in as sent by the client into a directory pathref fsp
730 : * and a relative smb_filename.
731 : */
732 691380 : static NTSTATUS filename_convert_dirfsp_nosymlink(
733 : TALLOC_CTX *mem_ctx,
734 : connection_struct *conn,
735 : const char *name_in,
736 : uint32_t ucf_flags,
737 : NTTIME twrp,
738 : struct files_struct **_dirfsp,
739 : struct smb_filename **_smb_fname,
740 : struct reparse_data_buffer **_symlink_err)
741 : {
742 691380 : struct smb_filename *smb_dirname = NULL;
743 691380 : struct smb_filename *smb_fname_rel = NULL;
744 691380 : struct smb_filename *smb_fname = NULL;
745 691380 : struct reparse_data_buffer *symlink_err = NULL;
746 691380 : const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
747 691380 : char *dirname = NULL;
748 691380 : const char *fname_rel = NULL;
749 691380 : const char *streamname = NULL;
750 691380 : char *saved_streamname = NULL;
751 691380 : struct files_struct *base_fsp = NULL;
752 10413 : bool ok;
753 691380 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
754 :
755 691380 : SMB_ASSERT(!(ucf_flags & UCF_DFS_PATHNAME));
756 :
757 691380 : if (is_fake_file_path(name_in)) {
758 21 : smb_fname = synthetic_smb_fname_split(mem_ctx, name_in, posix);
759 21 : if (smb_fname == NULL) {
760 0 : return NT_STATUS_NO_MEMORY;
761 : }
762 21 : smb_fname->st = (SMB_STRUCT_STAT){
763 : .st_ex_nlink = 1,
764 : .st_ex_mode = S_IFREG | 0644,
765 : };
766 21 : smb_fname->st.st_ex_btime =
767 : (struct timespec){0, SAMBA_UTIME_OMIT};
768 21 : smb_fname->st.st_ex_atime =
769 : (struct timespec){0, SAMBA_UTIME_OMIT};
770 21 : smb_fname->st.st_ex_mtime =
771 : (struct timespec){0, SAMBA_UTIME_OMIT};
772 21 : smb_fname->st.st_ex_ctime =
773 : (struct timespec){0, SAMBA_UTIME_OMIT};
774 :
775 21 : *_dirfsp = conn->cwd_fsp;
776 21 : *_smb_fname = smb_fname;
777 21 : return NT_STATUS_OK;
778 : }
779 :
780 : /*
781 : * Catch an invalid path of "." before we
782 : * call filename_split_lcomp(). We need to
783 : * do this as filename_split_lcomp() will
784 : * use "." for the missing relative component
785 : * when an empty name_in path is sent by
786 : * the client.
787 : */
788 691359 : if (ISDOT(name_in)) {
789 26 : status = NT_STATUS_OBJECT_NAME_INVALID;
790 26 : goto fail;
791 : }
792 :
793 691333 : ok = filename_split_lcomp(
794 : talloc_tos(),
795 : name_in,
796 : posix,
797 : &dirname,
798 : &fname_rel,
799 : &streamname);
800 691333 : if (!ok) {
801 0 : status = NT_STATUS_NO_MEMORY;
802 0 : goto fail;
803 : }
804 :
805 691333 : if ((streamname != NULL) &&
806 6432 : ((conn->fs_capabilities & FILE_NAMED_STREAMS) == 0)) {
807 8 : status = NT_STATUS_OBJECT_NAME_INVALID;
808 8 : goto fail;
809 : }
810 :
811 691325 : if (!posix) {
812 686834 : bool name_has_wild = ms_has_wild(dirname);
813 686834 : name_has_wild |= ms_has_wild(fname_rel);
814 686834 : if (name_has_wild) {
815 4456 : status = NT_STATUS_OBJECT_NAME_INVALID;
816 4456 : goto fail;
817 : }
818 : }
819 :
820 686869 : if (dirname[0] == '\0') {
821 117404 : status = synthetic_pathref(
822 : mem_ctx,
823 : conn->cwd_fsp,
824 : ".",
825 : NULL,
826 : NULL,
827 : 0,
828 : posix ? SMB_FILENAME_POSIX_PATH : 0,
829 : &smb_dirname);
830 : } else {
831 570963 : status = normalize_filename_case(conn, dirname, ucf_flags);
832 570963 : if (!NT_STATUS_IS_OK(status)) {
833 0 : DBG_ERR("normalize_filename_case %s failed: %s\n",
834 : dirname,
835 : nt_errstr(status));
836 0 : goto fail;
837 : }
838 :
839 570963 : status = openat_pathref_fsp_nosymlink(mem_ctx,
840 : conn,
841 : conn->cwd_fsp,
842 : dirname,
843 : twrp,
844 : posix,
845 : &smb_dirname,
846 : &symlink_err);
847 :
848 570963 : if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
849 0 : struct symlink_reparse_struct
850 62094 : *lnk = &symlink_err->parsed.lnk;
851 62094 : size_t unparsed = lnk->unparsed_path_length;
852 0 : size_t name_in_len, dirname_len;
853 :
854 62094 : name_in_len = strlen(name_in);
855 62094 : dirname_len = strlen(dirname);
856 :
857 62094 : SMB_ASSERT(name_in_len >= dirname_len);
858 :
859 62094 : unparsed += (name_in_len - dirname_len);
860 :
861 62094 : if (unparsed > UINT16_MAX) {
862 0 : status = NT_STATUS_BUFFER_OVERFLOW;
863 0 : goto fail;
864 : }
865 :
866 62094 : lnk->unparsed_path_length = unparsed;
867 62094 : *_symlink_err = symlink_err;
868 :
869 62094 : goto fail;
870 : }
871 : }
872 :
873 624775 : if (!NT_STATUS_IS_OK(status)) {
874 1028 : DBG_DEBUG("opening directory %s failed: %s\n",
875 : dirname,
876 : nt_errstr(status));
877 1028 : TALLOC_FREE(dirname);
878 :
879 1028 : if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
880 : /*
881 : * Except ACCESS_DENIED, everything else leads
882 : * to PATH_NOT_FOUND.
883 : */
884 1016 : status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
885 : }
886 :
887 1028 : goto fail;
888 : }
889 :
890 623747 : if (!VALID_STAT_OF_DIR(smb_dirname->st)) {
891 20 : status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
892 20 : goto fail;
893 : }
894 623727 : smb_dirname->fsp->fsp_flags.is_directory = true;
895 :
896 : /*
897 : * Only look at bad last component values
898 : * once we know we have a valid directory. That
899 : * way we won't confuse error messages from
900 : * opening the directory path with error
901 : * messages from a bad last component.
902 : */
903 :
904 : /* Relative filename can't be empty */
905 623727 : if (fname_rel[0] == '\0') {
906 0 : status = NT_STATUS_OBJECT_NAME_INVALID;
907 0 : goto fail;
908 : }
909 :
910 : /* Relative filename can't be ".." */
911 623727 : if (ISDOTDOT(fname_rel)) {
912 0 : status = NT_STATUS_OBJECT_NAME_INVALID;
913 0 : goto fail;
914 : }
915 : /* Relative name can only be dot if directory is empty. */
916 623727 : if (ISDOT(fname_rel) && dirname[0] != '\0') {
917 0 : status = NT_STATUS_OBJECT_NAME_INVALID;
918 0 : goto fail;
919 : }
920 :
921 623727 : TALLOC_FREE(dirname);
922 :
923 634131 : smb_fname_rel = synthetic_smb_fname(
924 : mem_ctx,
925 : fname_rel,
926 : streamname,
927 : NULL,
928 : twrp,
929 : posix ? SMB_FILENAME_POSIX_PATH : 0);
930 623727 : if (smb_fname_rel == NULL) {
931 0 : status = NT_STATUS_NO_MEMORY;
932 0 : goto fail;
933 : }
934 :
935 1184929 : if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
936 561202 : is_named_stream(smb_fname_rel)) {
937 : /*
938 : * Find the base_fsp first without the stream.
939 : */
940 6380 : saved_streamname = smb_fname_rel->stream_name;
941 6380 : smb_fname_rel->stream_name = NULL;
942 : }
943 :
944 623727 : status = normalize_filename_case(
945 : conn, smb_fname_rel->base_name, ucf_flags);
946 623727 : if (!NT_STATUS_IS_OK(status)) {
947 0 : DBG_ERR("normalize_filename_case %s failed: %s\n",
948 : smb_fname_rel->base_name,
949 : nt_errstr(status));
950 0 : goto fail;
951 : }
952 :
953 623727 : status = openat_pathref_fsp_lcomp(smb_dirname->fsp,
954 : smb_fname_rel,
955 : ucf_flags);
956 :
957 623727 : if (NT_STATUS_IS_OK(status) && S_ISLNK(smb_fname_rel->st.st_ex_mode)) {
958 :
959 : /*
960 : * Upper layers might need the link target. Here we
961 : * still have the relname around, get the symlink err.
962 : */
963 9488 : status = read_symlink_reparse(mem_ctx,
964 9488 : smb_dirname->fsp,
965 : smb_fname_rel,
966 : &symlink_err);
967 9488 : if (!NT_STATUS_IS_OK(status)) {
968 0 : DBG_DEBUG("Could not read symlink for %s: %s\n",
969 : smb_fname_str_dbg(
970 : smb_fname_rel->fsp->fsp_name),
971 : nt_errstr(status));
972 0 : goto fail;
973 : }
974 : }
975 :
976 623727 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
977 268607 : !VALID_STAT(smb_fname_rel->st)) {
978 :
979 268607 : char *normalized = NULL;
980 :
981 : /*
982 : * Creating a new file
983 : */
984 :
985 268607 : status = filename_convert_normalize_new(
986 : smb_fname_rel,
987 : conn,
988 : smb_fname_rel->base_name,
989 : &normalized);
990 268607 : if (!NT_STATUS_IS_OK(status)) {
991 0 : DBG_DEBUG("filename_convert_normalize_new failed: "
992 : "%s\n",
993 : nt_errstr(status));
994 0 : goto fail;
995 : }
996 268607 : if (normalized != NULL) {
997 48 : smb_fname_rel->base_name = normalized;
998 : }
999 :
1000 268607 : smb_fname_rel->stream_name = saved_streamname;
1001 :
1002 269483 : smb_fname = full_path_from_dirfsp_atname(
1003 268607 : mem_ctx, smb_dirname->fsp, smb_fname_rel);
1004 268607 : if (smb_fname == NULL) {
1005 0 : status = NT_STATUS_NO_MEMORY;
1006 0 : goto fail;
1007 : }
1008 268607 : goto done;
1009 : }
1010 :
1011 355120 : if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_OPEN_RESTRICTION)) {
1012 : /* A vetoed file, pretend it's not there */
1013 14 : status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1014 : }
1015 355120 : if (!NT_STATUS_IS_OK(status)) {
1016 24 : goto fail;
1017 : }
1018 :
1019 355096 : if (saved_streamname == NULL) {
1020 : /* smb_fname must be allocated off mem_ctx. */
1021 358455 : smb_fname = cp_smb_filename(mem_ctx,
1022 348928 : smb_fname_rel->fsp->fsp_name);
1023 348928 : if (smb_fname == NULL) {
1024 0 : goto fail;
1025 : }
1026 348928 : status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1027 348928 : if (!NT_STATUS_IS_OK(status)) {
1028 0 : goto fail;
1029 : }
1030 348928 : goto done;
1031 : }
1032 :
1033 6168 : base_fsp = smb_fname_rel->fsp;
1034 6168 : smb_fname_fsp_unlink(smb_fname_rel);
1035 6168 : SET_STAT_INVALID(smb_fname_rel->st);
1036 :
1037 6168 : smb_fname_rel->stream_name = saved_streamname;
1038 :
1039 6168 : status = open_stream_pathref_fsp(&base_fsp, smb_fname_rel);
1040 :
1041 6168 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1042 3821 : !conn->case_sensitive) {
1043 3821 : char *found = NULL;
1044 :
1045 3822 : status = get_real_stream_name(
1046 : smb_fname_rel,
1047 : base_fsp,
1048 3821 : smb_fname_rel->stream_name,
1049 : &found);
1050 :
1051 3821 : if (NT_STATUS_IS_OK(status)) {
1052 60 : smb_fname_rel->stream_name = found;
1053 60 : found = NULL;
1054 60 : status = open_stream_pathref_fsp(
1055 : &base_fsp, smb_fname_rel);
1056 : }
1057 : }
1058 :
1059 6168 : if (NT_STATUS_IS_OK(status)) {
1060 : /* smb_fname must be allocated off mem_ctx. */
1061 2359 : smb_fname = cp_smb_filename(mem_ctx,
1062 2359 : smb_fname_rel->fsp->fsp_name);
1063 2359 : if (smb_fname == NULL) {
1064 0 : goto fail;
1065 : }
1066 2359 : status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1067 2359 : if (!NT_STATUS_IS_OK(status)) {
1068 0 : goto fail;
1069 : }
1070 2359 : goto done;
1071 : }
1072 :
1073 3809 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1074 : /*
1075 : * Creating a new stream
1076 : *
1077 : * We should save the already-open base fsp for
1078 : * create_file_unixpath() somehow.
1079 : */
1080 3762 : smb_fname = full_path_from_dirfsp_atname(
1081 3761 : mem_ctx, smb_dirname->fsp, smb_fname_rel);
1082 3761 : if (smb_fname == NULL) {
1083 0 : status = NT_STATUS_NO_MEMORY;
1084 0 : goto fail;
1085 : }
1086 : /*
1087 : * When open_stream_pathref_fsp() returns
1088 : * NT_STATUS_OBJECT_NAME_NOT_FOUND, smb_fname_rel->fsp
1089 : * has been set to NULL, so we must free base_fsp separately
1090 : * to prevent fd-leaks when opening a stream that doesn't
1091 : * exist.
1092 : */
1093 3761 : fd_close(base_fsp);
1094 3761 : file_free(NULL, base_fsp);
1095 3761 : base_fsp = NULL;
1096 3761 : goto done;
1097 : }
1098 :
1099 48 : if (!NT_STATUS_IS_OK(status)) {
1100 48 : goto fail;
1101 : }
1102 :
1103 10404 : done:
1104 623655 : *_dirfsp = smb_dirname->fsp;
1105 623655 : *_smb_fname = smb_fname;
1106 623655 : *_symlink_err = symlink_err;
1107 :
1108 623655 : smb_fname_fsp_unlink(smb_fname_rel);
1109 623655 : TALLOC_FREE(smb_fname_rel);
1110 623655 : return NT_STATUS_OK;
1111 :
1112 67704 : fail:
1113 : /*
1114 : * If open_stream_pathref_fsp() returns an error, smb_fname_rel->fsp
1115 : * has been set to NULL, so we must free base_fsp separately
1116 : * to prevent fd-leaks when opening a stream that doesn't
1117 : * exist.
1118 : */
1119 67704 : if (base_fsp != NULL) {
1120 48 : fd_close(base_fsp);
1121 48 : file_free(NULL, base_fsp);
1122 48 : base_fsp = NULL;
1123 : }
1124 67704 : TALLOC_FREE(dirname);
1125 67704 : TALLOC_FREE(smb_dirname);
1126 67704 : TALLOC_FREE(smb_fname_rel);
1127 67704 : return status;
1128 : }
1129 :
1130 672830 : NTSTATUS filename_convert_dirfsp(
1131 : TALLOC_CTX *mem_ctx,
1132 : connection_struct *conn,
1133 : const char *name_in,
1134 : uint32_t ucf_flags,
1135 : NTTIME twrp,
1136 : struct files_struct **_dirfsp,
1137 : struct smb_filename **_smb_fname)
1138 : {
1139 672830 : struct reparse_data_buffer *symlink_err = NULL;
1140 672830 : struct symlink_reparse_struct *lnk = NULL;
1141 10413 : NTSTATUS status;
1142 672830 : char *target = NULL;
1143 672830 : char *safe_target = NULL;
1144 672830 : size_t symlink_redirects = 0;
1145 :
1146 691400 : next:
1147 691400 : if (symlink_redirects > 40) {
1148 20 : return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1149 : }
1150 :
1151 691380 : status = filename_convert_dirfsp_nosymlink(mem_ctx,
1152 : conn,
1153 : name_in,
1154 : ucf_flags,
1155 : twrp,
1156 : _dirfsp,
1157 : _smb_fname,
1158 : &symlink_err);
1159 :
1160 691380 : if (NT_STATUS_IS_OK(status) && S_ISLNK((*_smb_fname)->st.st_ex_mode)) {
1161 : /*
1162 : * lcomp is a symlink
1163 : */
1164 9488 : if (ucf_flags & UCF_LCOMP_LNK_OK) {
1165 740 : TALLOC_FREE(symlink_err);
1166 740 : return NT_STATUS_OK;
1167 : }
1168 8748 : close_file_free(NULL, _dirfsp, ERROR_CLOSE);
1169 8748 : status = NT_STATUS_STOPPED_ON_SYMLINK;
1170 : }
1171 :
1172 690640 : if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1173 619798 : return status;
1174 : }
1175 70842 : lnk = &symlink_err->parsed.lnk;
1176 :
1177 : /*
1178 : * If we're on an MSDFS share, see if this is
1179 : * an MSDFS link.
1180 : */
1181 121208 : if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
1182 50366 : strnequal(lnk->substitute_name, "msdfs:", 6))
1183 : {
1184 50366 : TALLOC_FREE(*_smb_fname);
1185 50366 : TALLOC_FREE(symlink_err);
1186 50366 : return NT_STATUS_PATH_NOT_COVERED;
1187 : }
1188 :
1189 20476 : if (!lp_follow_symlinks(SNUM(conn))) {
1190 28 : status = (lnk->unparsed_path_length == 0)
1191 : ? NT_STATUS_OBJECT_NAME_NOT_FOUND
1192 2 : : NT_STATUS_OBJECT_PATH_NOT_FOUND;
1193 28 : TALLOC_FREE(symlink_err);
1194 28 : return status;
1195 : }
1196 :
1197 : /*
1198 : * Right now, SMB2 and SMB1 always traverse symlinks
1199 : * within the share. SMB1+POSIX traverses non-terminal
1200 : * symlinks within the share.
1201 : *
1202 : * When we add SMB2+POSIX we need to return
1203 : * a NT_STATUS_STOPPED_ON_SYMLINK error here, using the
1204 : * symlink target data read below if SMB2+POSIX has
1205 : * UCF_POSIX_PATHNAMES set to cause the client to
1206 : * resolve all symlinks locally.
1207 : */
1208 :
1209 20448 : target = symlink_target_path(mem_ctx,
1210 : name_in,
1211 20448 : lnk->substitute_name,
1212 20448 : lnk->unparsed_path_length);
1213 20448 : if (target == NULL) {
1214 0 : return NT_STATUS_NO_MEMORY;
1215 : }
1216 :
1217 20448 : status = safe_symlink_target_path(mem_ctx,
1218 20448 : conn->connectpath,
1219 : NULL,
1220 : target,
1221 20448 : lnk->unparsed_path_length,
1222 : &safe_target);
1223 20448 : TALLOC_FREE(symlink_err);
1224 20448 : if (!NT_STATUS_IS_OK(status)) {
1225 1878 : return status;
1226 : }
1227 18570 : name_in = safe_target;
1228 :
1229 18570 : symlink_redirects += 1;
1230 :
1231 18570 : goto next;
1232 : }
1233 :
1234 5937675 : char *full_path_from_dirfsp_at_basename(TALLOC_CTX *mem_ctx,
1235 : const struct files_struct *dirfsp,
1236 : const char *at_base_name)
1237 : {
1238 5937675 : char *path = NULL;
1239 :
1240 5937675 : if (dirfsp == dirfsp->conn->cwd_fsp ||
1241 2465478 : ISDOT(dirfsp->fsp_name->base_name) || at_base_name[0] == '/') {
1242 3707397 : path = talloc_strdup(mem_ctx, at_base_name);
1243 : } else {
1244 2230278 : path = talloc_asprintf(mem_ctx,
1245 : "%s/%s",
1246 2220703 : dirfsp->fsp_name->base_name,
1247 : at_base_name);
1248 : }
1249 :
1250 5937675 : return path;
1251 : }
1252 :
1253 : /*
1254 : * Build the full path from a dirfsp and dirfsp relative name
1255 : */
1256 : struct smb_filename *
1257 5935527 : full_path_from_dirfsp_atname(TALLOC_CTX *mem_ctx,
1258 : const struct files_struct *dirfsp,
1259 : const struct smb_filename *atname)
1260 : {
1261 5935527 : struct smb_filename *fname = NULL;
1262 5935527 : char *path = NULL;
1263 :
1264 5958318 : path = full_path_from_dirfsp_at_basename(mem_ctx,
1265 : dirfsp,
1266 5935527 : atname->base_name);
1267 5935527 : if (path == NULL) {
1268 0 : return NULL;
1269 : }
1270 :
1271 5958318 : fname = synthetic_smb_fname(mem_ctx,
1272 : path,
1273 5935527 : atname->stream_name,
1274 : &atname->st,
1275 5935527 : atname->twrp,
1276 5935527 : atname->flags);
1277 5935527 : TALLOC_FREE(path);
1278 5935527 : if (fname == NULL) {
1279 0 : return NULL;
1280 : }
1281 :
1282 5912736 : return fname;
1283 : }
|