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
29static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
30				  connection_struct *conn,
31				  const char *orig_path,
32				  struct smb_filename *smb_fname);
33
34/****************************************************************************
35 Mangle the 2nd name and check if it is then equal to the first name.
36****************************************************************************/
37
38static bool mangled_equal(const char *name1,
39			const char *name2,
40			const struct share_params *p)
41{
42	char mname[13];
43
44	if (!name_to_8_3(name2, mname, False, p)) {
45		return False;
46	}
47	return strequal(name1, mname);
48}
49
50/****************************************************************************
51 Cope with the differing wildcard and non-wildcard error cases.
52****************************************************************************/
53
54static NTSTATUS determine_path_error(const char *name,
55			bool allow_wcard_last_component)
56{
57	const char *p;
58
59	if (!allow_wcard_last_component) {
60		/* Error code within a pathname. */
61		return NT_STATUS_OBJECT_PATH_NOT_FOUND;
62	}
63
64	/* We're terminating here so we
65	 * can be a little slower and get
66	 * the error code right. Windows
67	 * treats the last part of the pathname
68	 * separately I think, so if the last
69	 * component is a wildcard then we treat
70	 * this ./ as "end of component" */
71
72	p = strchr(name, '/');
73
74	if (!p && (ms_has_wild(name) || ISDOT(name))) {
75		/* Error code at the end of a pathname. */
76		return NT_STATUS_OBJECT_NAME_INVALID;
77	} else {
78		/* Error code within a pathname. */
79		return NT_STATUS_OBJECT_PATH_NOT_FOUND;
80	}
81}
82
83static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
84{
85	/* Ensure we catch all names with in "/."
86	   this is disallowed under Windows and
87	   in POSIX they've already been removed. */
88	const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
89	if (p) {
90		if (p[2] == '/') {
91			/* Error code within a pathname. */
92			return NT_STATUS_OBJECT_PATH_NOT_FOUND;
93		} else if (p[2] == '\0') {
94			/* Error code at the end of a pathname. */
95			return NT_STATUS_OBJECT_NAME_INVALID;
96		}
97	}
98	return NT_STATUS_OK;
99}
100
101/****************************************************************************
102This routine is called to convert names from the dos namespace to unix
103namespace. It needs to handle any case conversions, mangling, format changes,
104streams etc.
105
106We assume that we have already done a chdir() to the right "root" directory
107for this service.
108
109The function will return an NTSTATUS error if some part of the name except for
110the last part cannot be resolved, else NT_STATUS_OK.
111
112Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
113didn't get any fatal errors that should immediately terminate the calling SMB
114processing whilst resolving.
115
116If the UCF_SAVE_LCOMP flag is passed in, then the unmodified last component
117of the pathname is set in smb_filename->original_lcomp.
118
119If UCF_ALWAYS_ALLOW_WCARD_LCOMP is passed in, then a MS wildcard was detected
120and should be allowed in the last component of the path only.
121
122If the orig_path was a stream, smb_filename->base_name will point to the base
123filename, and smb_filename->stream_name will point to the stream name.  If
124orig_path was not a stream, then smb_filename->stream_name will be NULL.
125
126On exit from unix_convert, the smb_filename->st stat struct will be populated
127if the file exists and was found, if not this stat struct will be filled with
128zeros (and this can be detected by checking for nlinks = 0, which can never be
129true for any file).
130****************************************************************************/
131
132NTSTATUS unix_convert(TALLOC_CTX *ctx,
133		      connection_struct *conn,
134		      const char *orig_path,
135		      struct smb_filename **smb_fname_out,
136		      uint32_t ucf_flags)
137{
138	struct smb_filename *smb_fname = NULL;
139	char *start, *end;
140	char *dirpath = NULL;
141	char *stream = NULL;
142	bool component_was_mangled = False;
143	bool name_has_wildcard = False;
144	bool posix_pathnames = false;
145	bool allow_wcard_last_component =
146	    (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP);
147	bool save_last_component = ucf_flags & UCF_SAVE_LCOMP;
148	NTSTATUS status;
149	int ret = -1;
150
151	*smb_fname_out = NULL;
152
153	smb_fname = talloc_zero(ctx, struct smb_filename);
154	if (smb_fname == NULL) {
155		return NT_STATUS_NO_MEMORY;
156	}
157
158	if (conn->printer) {
159		/* we don't ever use the filenames on a printer share as a
160			filename - so don't convert them */
161		if (!(smb_fname->base_name = talloc_strdup(smb_fname,
162							   orig_path))) {
163			status = NT_STATUS_NO_MEMORY;
164			goto err;
165		}
166		goto done;
167	}
168
169	DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path));
170
171	/*
172	 * Conversion to basic unix format is already done in
173	 * check_path_syntax().
174	 */
175
176	/*
177	 * Names must be relative to the root of the service - any leading /.
178	 * and trailing /'s should have been trimmed by check_path_syntax().
179	 */
180
181#ifdef DEVELOPER
182	SMB_ASSERT(*orig_path != '/');
183#endif
184
185	/*
186	 * If we trimmed down to a single '\0' character
187	 * then we should use the "." directory to avoid
188	 * searching the cache, but not if we are in a
189	 * printing share.
190	 * As we know this is valid we can return true here.
191	 */
192
193	if (!*orig_path) {
194		if (!(smb_fname->base_name = talloc_strdup(smb_fname, "."))) {
195			status = NT_STATUS_NO_MEMORY;
196			goto err;
197		}
198		if (SMB_VFS_STAT(conn, smb_fname) != 0) {
199			status = map_nt_error_from_unix(errno);
200			goto err;
201		}
202		DEBUG(5, ("conversion finished \"\" -> %s\n",
203			  smb_fname->base_name));
204		goto done;
205	}
206
207	if (orig_path[0] == '.' && (orig_path[1] == '/' ||
208				orig_path[1] == '\0')) {
209		/* Start of pathname can't be "." only. */
210		if (orig_path[1] == '\0' || orig_path[2] == '\0') {
211			status = NT_STATUS_OBJECT_NAME_INVALID;
212		} else {
213			status =determine_path_error(&orig_path[2],
214			    allow_wcard_last_component);
215		}
216		goto err;
217	}
218
219	/* Start with the full orig_path as given by the caller. */
220	if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) {
221		DEBUG(0, ("talloc_strdup failed\n"));
222		status = NT_STATUS_NO_MEMORY;
223		goto err;
224	}
225
226	/*
227	 * Large directory fix normalization. If we're case sensitive, and
228	 * the case preserving parameters are set to "no", normalize the case of
229	 * the incoming filename from the client WHETHER IT EXISTS OR NOT !
230	 * This is in conflict with the current (3.0.20) man page, but is
231	 * what people expect from the "large directory howto". I'll update
232	 * the man page. Thanks to jht@samba.org for finding this. JRA.
233	 */
234
235	if (conn->case_sensitive && !conn->case_preserve &&
236			!conn->short_case_preserve) {
237		strnorm(smb_fname->base_name, lp_defaultcase(SNUM(conn)));
238	}
239
240	/*
241	 * Ensure saved_last_component is valid even if file exists.
242	 */
243
244	if(save_last_component) {
245		end = strrchr_m(smb_fname->base_name, '/');
246		if (end) {
247			smb_fname->original_lcomp = talloc_strdup(smb_fname,
248								  end + 1);
249		} else {
250			smb_fname->original_lcomp =
251			    talloc_strdup(smb_fname, smb_fname->base_name);
252		}
253		if (smb_fname->original_lcomp == NULL) {
254			status = NT_STATUS_NO_MEMORY;
255			goto err;
256		}
257	}
258
259	posix_pathnames = (lp_posix_pathnames() ||
260				(ucf_flags & UCF_POSIX_PATHNAMES));
261
262	/*
263	 * Strip off the stream, and add it back when we're done with the
264	 * base_name.
265	 */
266	if (!posix_pathnames) {
267		stream = strchr_m(smb_fname->base_name, ':');
268
269		if (stream != NULL) {
270			char *tmp = talloc_strdup(smb_fname, stream);
271			if (tmp == NULL) {
272				status = NT_STATUS_NO_MEMORY;
273				goto err;
274			}
275			/*
276			 * Since this is actually pointing into
277			 * smb_fname->base_name this truncates base_name.
278			 */
279			*stream = '\0';
280			stream = tmp;
281		}
282	}
283
284	start = smb_fname->base_name;
285
286	/*
287	 * If we're providing case insentive semantics or
288	 * the underlying filesystem is case insensitive,
289	 * then a case-normalized hit in the stat-cache is
290	 * authoratitive. JRA.
291	 *
292	 * Note: We're only checking base_name.  The stream_name will be
293	 * added and verified in build_stream_path().
294	 */
295
296	if((!conn->case_sensitive || !(conn->fs_capabilities &
297				       FILE_CASE_SENSITIVE_SEARCH)) &&
298	    stat_cache_lookup(conn, &smb_fname->base_name, &dirpath, &start,
299			      &smb_fname->st)) {
300		goto done;
301	}
302
303	/*
304	 * Make sure "dirpath" is an allocated string, we use this for
305	 * building the directories with asprintf and free it.
306	 */
307
308	if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) {
309		DEBUG(0, ("talloc_strdup failed\n"));
310		status = NT_STATUS_NO_MEMORY;
311		goto err;
312	}
313
314	/*
315	 * If we have a wildcard we must walk the path to
316	 * find where the error is, even if case sensitive
317	 * is true.
318	 */
319
320	name_has_wildcard = ms_has_wild(smb_fname->base_name);
321	if (name_has_wildcard && !allow_wcard_last_component) {
322		/* Wildcard not valid anywhere. */
323		status = NT_STATUS_OBJECT_NAME_INVALID;
324		goto fail;
325	}
326
327	DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
328		 smb_fname->base_name, dirpath, start));
329
330	if (!name_has_wildcard) {
331		/*
332		 * stat the name - if it exists then we can add the stream back (if
333		 * there was one) and be done!
334		 */
335
336		if (posix_pathnames) {
337			ret = SMB_VFS_LSTAT(conn, smb_fname);
338		} else {
339			ret = SMB_VFS_STAT(conn, smb_fname);
340		}
341
342		if (ret == 0) {
343			status = check_for_dot_component(smb_fname);
344			if (!NT_STATUS_IS_OK(status)) {
345				goto fail;
346			}
347			/* Add the path (not including the stream) to the cache. */
348			stat_cache_add(orig_path, smb_fname->base_name,
349				       conn->case_sensitive);
350			DEBUG(5,("conversion of base_name finished %s -> %s\n",
351				 orig_path, smb_fname->base_name));
352			goto done;
353		}
354
355		/*
356		 * A special case - if we don't have any wildcards or mangling chars and are case
357		 * sensitive or the underlying filesystem is case insentive then searching
358		 * won't help.
359		 */
360
361		if ((conn->case_sensitive || !(conn->fs_capabilities &
362					FILE_CASE_SENSITIVE_SEARCH)) &&
363				!mangle_is_mangled(smb_fname->base_name, conn->params)) {
364
365			status = check_for_dot_component(smb_fname);
366			if (!NT_STATUS_IS_OK(status)) {
367				goto fail;
368			}
369
370			/*
371			 * The stat failed. Could be ok as it could be
372 			 * a new file.
373 			 */
374
375			if (errno == ENOTDIR || errno == ELOOP) {
376				status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
377				goto fail;
378			} else if (errno == ENOENT) {
379				/*
380				 * Was it a missing last component ?
381				 * or a missing intermediate component ?
382				 */
383				struct smb_filename parent_fname;
384				ZERO_STRUCT(parent_fname);
385				if (!parent_dirname(ctx, smb_fname->base_name,
386							&parent_fname.base_name,
387							NULL)) {
388					status = NT_STATUS_NO_MEMORY;
389					goto fail;
390				}
391				if (posix_pathnames) {
392					ret = SMB_VFS_LSTAT(conn, &parent_fname);
393				} else {
394					ret = SMB_VFS_STAT(conn, &parent_fname);
395				}
396				if (ret == -1) {
397					if (errno == ENOTDIR ||
398							errno == ENOENT ||
399							errno == ELOOP) {
400						status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
401						goto fail;
402					}
403				}
404				/*
405				 * Missing last component is ok - new file.
406				 * Also deal with permission denied elsewhere.
407				 * Just drop out to done.
408				 */
409				goto done;
410			}
411		}
412	}
413
414	/*
415	 * is_mangled() was changed to look at an entire pathname, not
416	 * just a component. JRA.
417	 */
418
419	if (mangle_is_mangled(start, conn->params)) {
420		component_was_mangled = True;
421	}
422
423	/*
424	 * Now we need to recursively match the name against the real
425	 * directory structure.
426	 */
427
428	/*
429	 * Match each part of the path name separately, trying the names
430	 * as is first, then trying to scan the directory for matching names.
431	 */
432
433	for (; start ; start = (end?end+1:(char *)NULL)) {
434		/*
435		 * Pinpoint the end of this section of the filename.
436		 */
437		/* mb safe. '/' can't be in any encoded char. */
438		end = strchr(start, '/');
439
440		/*
441		 * Chop the name at this point.
442		 */
443		if (end) {
444			*end = 0;
445		}
446
447		if (save_last_component) {
448			TALLOC_FREE(smb_fname->original_lcomp);
449			smb_fname->original_lcomp = talloc_strdup(smb_fname,
450							end ? end + 1 : start);
451			if (!smb_fname->original_lcomp) {
452				DEBUG(0, ("talloc failed\n"));
453				status = NT_STATUS_NO_MEMORY;
454				goto err;
455			}
456		}
457
458		/* The name cannot have a component of "." */
459
460		if (ISDOT(start)) {
461			if (!end)  {
462				/* Error code at the end of a pathname. */
463				status = NT_STATUS_OBJECT_NAME_INVALID;
464			} else {
465				status = determine_path_error(end+1,
466						allow_wcard_last_component);
467			}
468			goto fail;
469		}
470
471		/* The name cannot have a wildcard if it's not
472		   the last component. */
473
474		name_has_wildcard = ms_has_wild(start);
475
476		/* Wildcards never valid within a pathname. */
477		if (name_has_wildcard && end) {
478			status = NT_STATUS_OBJECT_NAME_INVALID;
479			goto fail;
480		}
481
482		/*
483		 * Check if the name exists up to this point.
484		 */
485
486		if (posix_pathnames) {
487			ret = SMB_VFS_LSTAT(conn, smb_fname);
488		} else {
489			ret = SMB_VFS_STAT(conn, smb_fname);
490		}
491
492		if (ret == 0) {
493			/*
494			 * It exists. it must either be a directory or this must
495			 * be the last part of the path for it to be OK.
496			 */
497			if (end && !S_ISDIR(smb_fname->st.st_ex_mode)) {
498				/*
499				 * An intermediate part of the name isn't
500				 * a directory.
501				 */
502				DEBUG(5,("Not a dir %s\n",start));
503				*end = '/';
504				/*
505				 * We need to return the fact that the
506				 * intermediate name resolution failed. This
507				 * is used to return an error of ERRbadpath
508				 * rather than ERRbadfile. Some Windows
509				 * applications depend on the difference between
510				 * these two errors.
511				 */
512				status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
513				goto fail;
514			}
515
516		} else {
517			char *found_name = NULL;
518
519			/* Stat failed - ensure we don't use it. */
520			SET_STAT_INVALID(smb_fname->st);
521
522			/*
523			 * Reset errno so we can detect
524			 * directory open errors.
525			 */
526			errno = 0;
527
528			/*
529			 * Try to find this part of the path in the directory.
530			 */
531
532			if (name_has_wildcard ||
533			    (get_real_filename(conn, dirpath, start,
534					       talloc_tos(),
535					       &found_name) == -1)) {
536				char *unmangled;
537
538				if (end) {
539					/*
540					 * An intermediate part of the name
541					 * can't be found.
542					 */
543					DEBUG(5,("Intermediate not found %s\n",
544							start));
545					*end = '/';
546
547					/*
548					 * We need to return the fact that the
549					 * intermediate name resolution failed.
550					 * This is used to return an error of
551					 * ERRbadpath rather than ERRbadfile.
552					 * Some Windows applications depend on
553					 * the difference between these two
554					 * errors.
555					 */
556
557					/*
558					 * ENOENT, ENOTDIR and ELOOP all map
559					 * to NT_STATUS_OBJECT_PATH_NOT_FOUND
560					 * in the filename walk.
561					 */
562
563					if (errno == ENOENT ||
564							errno == ENOTDIR ||
565							errno == ELOOP) {
566						status =
567						NT_STATUS_OBJECT_PATH_NOT_FOUND;
568					}
569					else {
570						status =
571						map_nt_error_from_unix(errno);
572					}
573					goto fail;
574				}
575
576				/*
577				 * ENOENT/EACCESS are the only valid errors
578				 * here. EACCESS needs handling here for
579				 * "dropboxes", i.e. directories where users
580				 * can only put stuff with permission -wx.
581				 */
582				if ((errno != 0) && (errno != ENOENT)
583				    && (errno != EACCES)) {
584					/*
585					 * ENOTDIR and ELOOP both map to
586					 * NT_STATUS_OBJECT_PATH_NOT_FOUND
587					 * in the filename walk.
588					 */
589					if (errno == ENOTDIR ||
590							errno == ELOOP) {
591						status =
592						NT_STATUS_OBJECT_PATH_NOT_FOUND;
593					} else {
594						status =
595						map_nt_error_from_unix(errno);
596					}
597					goto fail;
598				}
599
600				/*
601				 * Just the last part of the name doesn't exist.
602				 * We need to strupper() or strlower() it as
603				 * this conversion may be used for file creation
604				 * purposes. Fix inspired by
605				 * Thomas Neumann <t.neumann@iku-ag.de>.
606				 */
607				if (!conn->case_preserve ||
608				    (mangle_is_8_3(start, False,
609						   conn->params) &&
610						 !conn->short_case_preserve)) {
611					strnorm(start,
612						lp_defaultcase(SNUM(conn)));
613				}
614
615				/*
616				 * check on the mangled stack to see if we can
617				 * recover the base of the filename.
618				 */
619
620				if (mangle_is_mangled(start, conn->params)
621				    && mangle_lookup_name_from_8_3(ctx,
622					    		start,
623							&unmangled,
624							conn->params)) {
625					char *tmp;
626					size_t start_ofs =
627					    start - smb_fname->base_name;
628
629					if (*dirpath != '\0') {
630						tmp = talloc_asprintf(
631							smb_fname, "%s/%s",
632							dirpath, unmangled);
633						TALLOC_FREE(unmangled);
634					}
635					else {
636						tmp = unmangled;
637					}
638					if (tmp == NULL) {
639						DEBUG(0, ("talloc failed\n"));
640						status = NT_STATUS_NO_MEMORY;
641						goto err;
642					}
643					TALLOC_FREE(smb_fname->base_name);
644					smb_fname->base_name = tmp;
645					start =
646					    smb_fname->base_name + start_ofs;
647					end = start + strlen(start);
648				}
649
650				DEBUG(5,("New file %s\n",start));
651				goto done;
652			}
653
654
655			/*
656			 * Restore the rest of the string. If the string was
657			 * mangled the size may have changed.
658			 */
659			if (end) {
660				char *tmp;
661				size_t start_ofs =
662				    start - smb_fname->base_name;
663
664				if (*dirpath != '\0') {
665					tmp = talloc_asprintf(smb_fname,
666						"%s/%s/%s", dirpath,
667						found_name, end+1);
668				}
669				else {
670					tmp = talloc_asprintf(smb_fname,
671						"%s/%s", found_name,
672						end+1);
673				}
674				if (tmp == NULL) {
675					DEBUG(0, ("talloc_asprintf failed\n"));
676					status = NT_STATUS_NO_MEMORY;
677					goto err;
678				}
679				TALLOC_FREE(smb_fname->base_name);
680				smb_fname->base_name = tmp;
681				start = smb_fname->base_name + start_ofs;
682				end = start + strlen(found_name);
683				*end = '\0';
684			} else {
685				char *tmp;
686				size_t start_ofs =
687				    start - smb_fname->base_name;
688
689				if (*dirpath != '\0') {
690					tmp = talloc_asprintf(smb_fname,
691						"%s/%s", dirpath,
692						found_name);
693				} else {
694					tmp = talloc_strdup(smb_fname,
695						found_name);
696				}
697				if (tmp == NULL) {
698					DEBUG(0, ("talloc failed\n"));
699					status = NT_STATUS_NO_MEMORY;
700					goto err;
701				}
702				TALLOC_FREE(smb_fname->base_name);
703				smb_fname->base_name = tmp;
704				start = smb_fname->base_name + start_ofs;
705
706				/*
707				 * We just scanned for, and found the end of
708				 * the path. We must return a valid stat struct
709				 * if it exists. JRA.
710				 */
711
712				if (posix_pathnames) {
713					ret = SMB_VFS_LSTAT(conn, smb_fname);
714				} else {
715					ret = SMB_VFS_STAT(conn, smb_fname);
716				}
717
718				if (ret != 0) {
719					SET_STAT_INVALID(smb_fname->st);
720				}
721			}
722
723			TALLOC_FREE(found_name);
724		} /* end else */
725
726#ifdef DEVELOPER
727		/*
728		 * This sucks!
729		 * We should never provide different behaviors
730		 * depending on DEVELOPER!!!
731		 */
732		if (VALID_STAT(smb_fname->st)) {
733			bool delete_pending;
734			get_file_infos(vfs_file_id_from_sbuf(conn,
735							     &smb_fname->st),
736				       &delete_pending, NULL);
737			if (delete_pending) {
738				status = NT_STATUS_DELETE_PENDING;
739				goto fail;
740			}
741		}
742#endif
743
744		/*
745		 * Add to the dirpath that we have resolved so far.
746		 */
747
748		if (*dirpath != '\0') {
749			char *tmp = talloc_asprintf(ctx,
750					"%s/%s", dirpath, start);
751			if (!tmp) {
752				DEBUG(0, ("talloc_asprintf failed\n"));
753				status = NT_STATUS_NO_MEMORY;
754				goto err;
755			}
756			TALLOC_FREE(dirpath);
757			dirpath = tmp;
758		}
759		else {
760			TALLOC_FREE(dirpath);
761			if (!(dirpath = talloc_strdup(ctx,start))) {
762				DEBUG(0, ("talloc_strdup failed\n"));
763				status = NT_STATUS_NO_MEMORY;
764				goto err;
765			}
766		}
767
768		/*
769		 * Cache the dirpath thus far. Don't cache a name with mangled
770		 * or wildcard components as this can change the size.
771		 */
772		if(!component_was_mangled && !name_has_wildcard) {
773			stat_cache_add(orig_path, dirpath,
774					conn->case_sensitive);
775		}
776
777		/*
778		 * Restore the / that we wiped out earlier.
779		 */
780		if (end) {
781			*end = '/';
782		}
783	}
784
785	/*
786	 * Cache the full path. Don't cache a name with mangled or wildcard
787	 * components as this can change the size.
788	 */
789
790	if(!component_was_mangled && !name_has_wildcard) {
791		stat_cache_add(orig_path, smb_fname->base_name,
792			       conn->case_sensitive);
793	}
794
795	/*
796	 * The name has been resolved.
797	 */
798
799	DEBUG(5,("conversion finished %s -> %s\n", orig_path,
800		 smb_fname->base_name));
801
802 done:
803	/* Add back the stream if one was stripped off originally. */
804	if (stream != NULL) {
805		smb_fname->stream_name = stream;
806
807		/* Check path now that the base_name has been converted. */
808		status = build_stream_path(ctx, conn, orig_path, smb_fname);
809		if (!NT_STATUS_IS_OK(status)) {
810			goto fail;
811		}
812	}
813	TALLOC_FREE(dirpath);
814	*smb_fname_out = smb_fname;
815	return NT_STATUS_OK;
816 fail:
817	DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start));
818	if (*dirpath != '\0') {
819		smb_fname->base_name = talloc_asprintf(smb_fname, "%s/%s",
820						       dirpath, start);
821	} else {
822		smb_fname->base_name = talloc_strdup(smb_fname, start);
823	}
824	if (!smb_fname->base_name) {
825		DEBUG(0, ("talloc_asprintf failed\n"));
826		status = NT_STATUS_NO_MEMORY;
827		goto err;
828	}
829
830	*smb_fname_out = smb_fname;
831	TALLOC_FREE(dirpath);
832	return status;
833 err:
834	TALLOC_FREE(smb_fname);
835	return status;
836}
837
838/****************************************************************************
839 Check a filename - possibly calling check_reduced_name.
840 This is called by every routine before it allows an operation on a filename.
841 It does any final confirmation necessary to ensure that the filename is
842 a valid one for the user to access.
843****************************************************************************/
844
845NTSTATUS check_name(connection_struct *conn, const char *name)
846{
847	if (IS_VETO_PATH(conn, name))  {
848		/* Is it not dot or dot dot. */
849		if (!((name[0] == '.') && (!name[1] ||
850					(name[1] == '.' && !name[2])))) {
851			DEBUG(5,("check_name: file path name %s vetoed\n",
852						name));
853			return map_nt_error_from_unix(ENOENT);
854		}
855	}
856
857	if (!lp_widelinks(SNUM(conn)) || !lp_symlinks(SNUM(conn))) {
858		NTSTATUS status = check_reduced_name(conn,name);
859		if (!NT_STATUS_IS_OK(status)) {
860			DEBUG(5,("check_name: name %s failed with %s\n",name,
861						nt_errstr(status)));
862			return status;
863		}
864	}
865
866	return NT_STATUS_OK;
867}
868
869/****************************************************************************
870 Check if two filenames are equal.
871 This needs to be careful about whether we are case sensitive.
872****************************************************************************/
873
874static bool fname_equal(const char *name1, const char *name2,
875		bool case_sensitive)
876{
877	/* Normal filename handling */
878	if (case_sensitive) {
879		return(strcmp(name1,name2) == 0);
880	}
881
882	return(strequal(name1,name2));
883}
884
885/****************************************************************************
886 Scan a directory to find a filename, matching without case sensitivity.
887 If the name looks like a mangled name then try via the mangling functions
888****************************************************************************/
889
890static int get_real_filename_full_scan(connection_struct *conn,
891				       const char *path, const char *name,
892				       bool mangled,
893				       TALLOC_CTX *mem_ctx, char **found_name)
894{
895	struct smb_Dir *cur_dir;
896	const char *dname = NULL;
897	char *talloced = NULL;
898	char *unmangled_name = NULL;
899	long curpos;
900
901	/* handle null paths */
902	if ((path == NULL) || (*path == 0)) {
903		path = ".";
904	}
905
906	/* If we have a case-sensitive filesystem, it doesn't do us any
907	 * good to search for a name. If a case variation of the name was
908	 * there, then the original stat(2) would have found it.
909	 */
910	if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
911		errno = ENOENT;
912		return -1;
913	}
914
915	/*
916	 * The incoming name can be mangled, and if we de-mangle it
917	 * here it will not compare correctly against the filename (name2)
918	 * read from the directory and then mangled by the name_to_8_3()
919	 * call. We need to mangle both names or neither.
920	 * (JRA).
921	 *
922	 * Fix for bug found by Dina Fine. If in case sensitive mode then
923	 * the mangle cache is no good (3 letter extension could be wrong
924	 * case - so don't demangle in this case - leave as mangled and
925	 * allow the mangling of the directory entry read (which is done
926	 * case insensitively) to match instead. This will lead to more
927	 * false positive matches but we fail completely without it. JRA.
928	 */
929
930	if (mangled && !conn->case_sensitive) {
931		mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
932						       &unmangled_name,
933						       conn->params);
934		if (!mangled) {
935			/* Name is now unmangled. */
936			name = unmangled_name;
937		}
938	}
939
940	/* open the directory */
941	if (!(cur_dir = OpenDir(talloc_tos(), conn, path, NULL, 0))) {
942		DEBUG(3,("scan dir didn't open dir [%s]\n",path));
943		TALLOC_FREE(unmangled_name);
944		return -1;
945	}
946
947	/* now scan for matching names */
948	curpos = 0;
949	while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {
950
951		/* Is it dot or dot dot. */
952		if (ISDOT(dname) || ISDOTDOT(dname)) {
953			TALLOC_FREE(talloced);
954			continue;
955		}
956
957		/*
958		 * At this point dname is the unmangled name.
959		 * name is either mangled or not, depending on the state
960		 * of the "mangled" variable. JRA.
961		 */
962
963		/*
964		 * Check mangled name against mangled name, or unmangled name
965		 * against unmangled name.
966		 */
967
968		if ((mangled && mangled_equal(name,dname,conn->params)) ||
969			fname_equal(name, dname, conn->case_sensitive)) {
970			/* we've found the file, change it's name and return */
971			*found_name = talloc_strdup(mem_ctx, dname);
972			TALLOC_FREE(unmangled_name);
973			TALLOC_FREE(cur_dir);
974			if (!*found_name) {
975				errno = ENOMEM;
976				TALLOC_FREE(talloced);
977				return -1;
978			}
979			TALLOC_FREE(talloced);
980			return 0;
981		}
982		TALLOC_FREE(talloced);
983	}
984
985	TALLOC_FREE(unmangled_name);
986	TALLOC_FREE(cur_dir);
987	errno = ENOENT;
988	return -1;
989}
990
991/****************************************************************************
992 Wrapper around the vfs get_real_filename and the full directory scan
993 fallback.
994****************************************************************************/
995
996int get_real_filename(connection_struct *conn, const char *path,
997		      const char *name, TALLOC_CTX *mem_ctx,
998		      char **found_name)
999{
1000	int ret;
1001	bool mangled;
1002
1003	mangled = mangle_is_mangled(name, conn->params);
1004
1005	if (mangled) {
1006		return get_real_filename_full_scan(conn, path, name, mangled,
1007						   mem_ctx, found_name);
1008	}
1009
1010	/* Try the vfs first to take advantage of case-insensitive stat. */
1011	ret = SMB_VFS_GET_REAL_FILENAME(conn, path, name, mem_ctx, found_name);
1012
1013	/*
1014	 * If the case-insensitive stat was successful, or returned an error
1015	 * other than EOPNOTSUPP then there is no need to fall back on the
1016	 * full directory scan.
1017	 */
1018	if (ret == 0 || (ret == -1 && errno != EOPNOTSUPP)) {
1019		return ret;
1020	}
1021
1022	return get_real_filename_full_scan(conn, path, name, mangled, mem_ctx,
1023					   found_name);
1024}
1025
1026static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
1027				  connection_struct *conn,
1028				  const char *orig_path,
1029				  struct smb_filename *smb_fname)
1030{
1031	NTSTATUS status;
1032	unsigned int i, num_streams;
1033	struct stream_struct *streams = NULL;
1034
1035	if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1036		DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1037		return NT_STATUS_OK;
1038	}
1039
1040	if (errno != ENOENT) {
1041		DEBUG(10, ("vfs_stat failed: %s\n", strerror(errno)));
1042		status = map_nt_error_from_unix(errno);
1043		goto fail;
1044	}
1045
1046	/* Fall back to a case-insensitive scan of all streams on the file. */
1047	status = SMB_VFS_STREAMINFO(conn, NULL, smb_fname->base_name, mem_ctx,
1048				    &num_streams, &streams);
1049
1050	if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1051		SET_STAT_INVALID(smb_fname->st);
1052		return NT_STATUS_OK;
1053	}
1054
1055	if (!NT_STATUS_IS_OK(status)) {
1056		DEBUG(10, ("vfs_streaminfo failed: %s\n", nt_errstr(status)));
1057		goto fail;
1058	}
1059
1060	for (i=0; i<num_streams; i++) {
1061		DEBUG(10, ("comparing [%s] and [%s]: ",
1062			   smb_fname->stream_name, streams[i].name));
1063		if (fname_equal(smb_fname->stream_name, streams[i].name,
1064				conn->case_sensitive)) {
1065			DEBUGADD(10, ("equal\n"));
1066			break;
1067		}
1068		DEBUGADD(10, ("not equal\n"));
1069	}
1070
1071	/* Couldn't find the stream. */
1072	if (i == num_streams) {
1073		SET_STAT_INVALID(smb_fname->st);
1074		TALLOC_FREE(streams);
1075		return NT_STATUS_OK;
1076	}
1077
1078	DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n",
1079		smb_fname->stream_name, streams[i].name));
1080
1081
1082	TALLOC_FREE(smb_fname->stream_name);
1083	smb_fname->stream_name = talloc_strdup(smb_fname, streams[i].name);
1084	if (smb_fname->stream_name == NULL) {
1085		status = NT_STATUS_NO_MEMORY;
1086		goto fail;
1087	}
1088
1089	SET_STAT_INVALID(smb_fname->st);
1090
1091	if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1092		DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1093	}
1094	status = NT_STATUS_OK;
1095 fail:
1096	TALLOC_FREE(streams);
1097	return status;
1098}
1099
1100/**
1101 * Go through all the steps to validate a filename.
1102 *
1103 * @param ctx		talloc_ctx to allocate memory with.
1104 * @param conn		connection struct for vfs calls.
1105 * @param dfs_path	Whether this path requires dfs resolution.
1106 * @param name_in	The unconverted name.
1107 * @param ucf_flags	flags to pass through to unix_convert().
1108 *			UCF_ALWAYS_ALLOW_WCARD_LCOMP will be OR'd in if
1109 *			p_cont_wcard != NULL and is true and
1110 *			UCF_COND_ALLOW_WCARD_LCOMP.
1111 * @param p_cont_wcard	If not NULL, will be set to true if the dfs path
1112 *			resolution detects a wildcard.
1113 * @param pp_smb_fname	The final converted name will be allocated if the
1114 *			return is NT_STATUS_OK.
1115 *
1116 * @return NT_STATUS_OK if all operations completed succesfully, appropriate
1117 * 	   error otherwise.
1118 */
1119NTSTATUS filename_convert(TALLOC_CTX *ctx,
1120				connection_struct *conn,
1121				bool dfs_path,
1122				const char *name_in,
1123				uint32_t ucf_flags,
1124				bool *ppath_contains_wcard,
1125				struct smb_filename **pp_smb_fname)
1126{
1127	NTSTATUS status;
1128	bool allow_wcards = (ucf_flags & (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
1129	char *fname = NULL;
1130
1131	*pp_smb_fname = NULL;
1132
1133	status = resolve_dfspath_wcard(ctx, conn,
1134				dfs_path,
1135				name_in,
1136				allow_wcards,
1137				&fname,
1138				ppath_contains_wcard);
1139	if (!NT_STATUS_IS_OK(status)) {
1140		DEBUG(10,("filename_convert: resolve_dfspath failed "
1141			"for name %s with %s\n",
1142			name_in,
1143			nt_errstr(status) ));
1144		return status;
1145	}
1146
1147	if (is_fake_file_path(name_in)) {
1148		SMB_STRUCT_STAT st;
1149		ZERO_STRUCT(st);
1150		st.st_ex_nlink = 1;
1151		status = create_synthetic_smb_fname_split(ctx,
1152							  name_in,
1153							  &st,
1154							  pp_smb_fname);
1155		return status;
1156	}
1157
1158	/*
1159	 * If the caller conditionally allows wildcard lookups, only add the
1160	 * always allow if the path actually does contain a wildcard.
1161	 */
1162	if (ucf_flags & UCF_COND_ALLOW_WCARD_LCOMP &&
1163	    ppath_contains_wcard != NULL && *ppath_contains_wcard) {
1164		ucf_flags |= UCF_ALWAYS_ALLOW_WCARD_LCOMP;
1165	}
1166
1167	status = unix_convert(ctx, conn, fname, pp_smb_fname, ucf_flags);
1168	if (!NT_STATUS_IS_OK(status)) {
1169		DEBUG(10,("filename_convert: unix_convert failed "
1170			"for name %s with %s\n",
1171			fname,
1172			nt_errstr(status) ));
1173		return status;
1174	}
1175
1176	status = check_name(conn, (*pp_smb_fname)->base_name);
1177	if (!NT_STATUS_IS_OK(status)) {
1178		DEBUG(3,("filename_convert: check_name failed "
1179			"for name %s with %s\n",
1180			smb_fname_str_dbg(*pp_smb_fname),
1181			nt_errstr(status) ));
1182		TALLOC_FREE(*pp_smb_fname);
1183		return status;
1184	}
1185
1186	return status;
1187}
1188