Example #1
0
static int sys_acl_set_file_tdb(vfs_handle_struct *handle,
                                const char *path,
                                SMB_ACL_TYPE_T type,
                                SMB_ACL_T theacl)
{
    SMB_STRUCT_STAT sbuf;
    struct db_context *db;
    int ret = -1;

    SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);

    if (lp_posix_pathnames()) {
        ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf);
    } else {
        ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
    }

    if (ret == -1) {
        return -1;
    }

    ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle,
                                        path,
                                        type,
                                        theacl);
    if (ret == -1) {
        return -1;
    }

    acl_tdb_delete(handle, db, &sbuf);
    return 0;
}
Example #2
0
static int unlink_acl_tdb(vfs_handle_struct *handle,
                          const struct smb_filename *smb_fname)
{
    struct smb_filename *smb_fname_tmp = NULL;
    struct db_context *db = acl_db;
    NTSTATUS status;
    int ret = -1;

    status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
    if (!NT_STATUS_IS_OK(status)) {
        errno = map_errno_from_nt_status(status);
        goto out;
    }

    if (lp_posix_pathnames()) {
        ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
    } else {
        ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
    }

    if (ret == -1) {
        goto out;
    }

    ret = unlink_acl_common(handle, smb_fname_tmp);

    if (ret == -1) {
        goto out;
    }

    acl_tdb_delete(handle, db, &smb_fname_tmp->st);
out:
    return ret;
}
Example #3
0
/**
 * XXX: This is temporary and there should be no callers of this once
 * smb_filename is plumbed through all path based operations.
 */
NTSTATUS create_synthetic_smb_fname_split(TALLOC_CTX *ctx,
					  const char *fname,
					  const SMB_STRUCT_STAT *psbuf,
					  struct smb_filename **smb_fname_out)
{
	NTSTATUS status;
	const char *stream_name = NULL;
	char *base_name = NULL;

	if (!lp_posix_pathnames()) {
		stream_name = strchr_m(fname, ':');
	}

	/* Setup the base_name/stream_name. */
	if (stream_name) {
		base_name = talloc_strndup(ctx, fname,
					   PTR_DIFF(stream_name, fname));
	} else {
		base_name = talloc_strdup(ctx, fname);
	}

	if (!base_name) {
		return NT_STATUS_NO_MEMORY;
	}

	status = create_synthetic_smb_fname(ctx, base_name, stream_name, psbuf,
					    smb_fname_out);
	TALLOC_FREE(base_name);
	return status;
}
Example #4
0
static int unlink_acl_tdb(vfs_handle_struct *handle,
			  const struct smb_filename *smb_fname)
{
	struct smb_filename *smb_fname_tmp = NULL;
	struct db_context *db = acl_db;
	int ret = -1;

	smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
	if (smb_fname_tmp == NULL) {
		errno = ENOMEM;
		goto out;
	}

	if (lp_posix_pathnames()) {
		ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
	} else {
		ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
	}

	if (ret == -1) {
		goto out;
	}

	ret = unlink_acl_common(handle, smb_fname_tmp);

	if (ret == -1) {
		goto out;
	}

	acl_tdb_delete(handle, db, &smb_fname_tmp->st);
 out:
	return ret;
}
Example #5
0
static int rmdir_acl_tdb(vfs_handle_struct *handle, const char *path)
{

    SMB_STRUCT_STAT sbuf;
    struct db_context *db = acl_db;
    int ret = -1;

    if (lp_posix_pathnames()) {
        ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf);
    } else {
        ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
    }

    if (ret == -1) {
        return -1;
    }

    ret = rmdir_acl_common(handle, path);
    if (ret == -1) {
        return -1;
    }

    acl_tdb_delete(handle, db, &sbuf);
    return 0;
}
Example #6
0
static int rmdir_acl_tdb(vfs_handle_struct *handle, const char *path)
{

    SMB_STRUCT_STAT sbuf;
    struct db_context *db;
    int ret = -1;

    SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);

    if (lp_posix_pathnames()) {
        ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf);
    } else {
        ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
    }

    if (ret == -1) {
        return -1;
    }

    ret = SMB_VFS_NEXT_RMDIR(handle, path);
    if (ret == -1) {
        return -1;
    }

    acl_tdb_delete(handle, db, &sbuf);
    return 0;
}
/**
 * XXX: This is temporary and there should be no callers of this once
 * smb_filename is plumbed through all path based operations.
 */
struct smb_filename *synthetic_smb_fname_split(TALLOC_CTX *ctx,
					       const char *fname,
					       const SMB_STRUCT_STAT *psbuf)
{
	const char *stream_name = NULL;
	char *base_name = NULL;
	struct smb_filename *ret;

	if (!lp_posix_pathnames()) {
		stream_name = strchr_m(fname, ':');
	}

	/* Setup the base_name/stream_name. */
	if (stream_name) {
		base_name = talloc_strndup(ctx, fname,
					   PTR_DIFF(stream_name, fname));
	} else {
		base_name = talloc_strdup(ctx, fname);
	}

	if (!base_name) {
		return NULL;
	}

	ret = synthetic_smb_fname(ctx, base_name, stream_name, psbuf);
	TALLOC_FREE(base_name);
	return ret;
}
Example #8
0
/*
 * On unlink we need to delete the tdb record
 */
static int posix_eadb_unlink(vfs_handle_struct *handle,
			    const struct smb_filename *smb_fname)
{
	struct smb_filename *smb_fname_tmp = NULL;
	int ret = -1;

	struct tdb_wrap *ea_tdb;

	SMB_VFS_HANDLE_GET_DATA(handle, ea_tdb, struct tdb_wrap, return -1);

	smb_fname_tmp = cp_smb_filename(talloc_tos(), smb_fname);
	if (smb_fname_tmp == NULL) {
		errno = ENOMEM;
		return -1;
	}

	if (lp_posix_pathnames()) {
		ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_tmp);
	} else {
		ret = SMB_VFS_NEXT_STAT(handle, smb_fname_tmp);
	}
	if (ret == -1) {
		goto out;
	}

	if (smb_fname_tmp->st.st_ex_nlink == 1) {
		NTSTATUS status;

		/* Only remove record on last link to file. */

		if (tdb_transaction_start(ea_tdb->tdb) != 0) {
			ret = -1;
			goto out;
		}

		status = unlink_posix_eadb_raw(ea_tdb, smb_fname->base_name, -1);
		if (!NT_STATUS_IS_OK(status)) {
			tdb_transaction_cancel(ea_tdb->tdb);
			ret = -1;
			goto out;
		}
	}

	ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);

	if (ret == -1) {
		tdb_transaction_cancel(ea_tdb->tdb);
		goto out;
	} else {
		if (tdb_transaction_commit(ea_tdb->tdb) != 0) {
			ret = -1;
			goto out;
		}
	}

out:
	TALLOC_FREE(smb_fname_tmp);
	return ret;
}
Example #9
0
static int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
			const char *name, mode_t mode)
{
	if (lp_posix_pathnames()) {
		/* Only allow this on POSIX pathnames. */
		return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
	}
	return 0;
}
static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
			       SMB_STRUCT_STAT *sbuf)
{
	struct smb_filename *smb_fname_base = NULL;
	NTSTATUS status;
	int ret = -1;
	struct stream_io *io = (struct stream_io *)
		VFS_FETCH_FSP_EXTENSION(handle, fsp);

	DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp->fh->fd));

	if (io == NULL || fsp->base_fsp == NULL) {
		return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
	}

	if (!streams_xattr_recheck(io)) {
		return -1;
	}

	/* Create an smb_filename with stream_name == NULL. */
	status = create_synthetic_smb_fname(talloc_tos(),
					    io->base,
					    NULL, NULL,
					    &smb_fname_base);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		return -1;
	}

	if (lp_posix_pathnames()) {
		ret = SMB_VFS_LSTAT(handle->conn, smb_fname_base);
	} else {
		ret = SMB_VFS_STAT(handle->conn, smb_fname_base);
	}
	*sbuf = smb_fname_base->st;
	TALLOC_FREE(smb_fname_base);

	if (ret == -1) {
		return -1;
	}

	sbuf->st_ex_size = get_xattr_size(handle->conn, fsp->base_fsp,
					io->base, io->xattr_name);
	if (sbuf->st_ex_size == -1) {
		return -1;
	}

	DEBUG(10, ("sbuf->st_ex_size = %d\n", (int)sbuf->st_ex_size));

	sbuf->st_ex_ino = stream_inode(sbuf, io->xattr_name);
	sbuf->st_ex_mode &= ~S_IFMT;
        sbuf->st_ex_mode |= S_IFREG;
        sbuf->st_ex_blocks = sbuf->st_ex_size / STAT_ST_BLOCKSIZE + 1;

	return 0;
}
/****************************************************************************
 Simple check to determine if the filename is a stream.
 ***************************************************************************/
bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname)
{
	/* stream_name must always be NULL if there is no stream. */
	if (smb_fname->stream_name) {
		SMB_ASSERT(smb_fname->stream_name[0] != '\0');
	}

	if (lp_posix_pathnames()) {
		return false;
	}

	return smb_fname->stream_name != NULL;
}
Example #12
0
bool ea_list_has_invalid_name(struct ea_list *ea_list)
{
	if (lp_posix_pathnames()) {
		return false;
	}

	for (;ea_list; ea_list = ea_list->next) {
		if (is_invalid_windows_ea_name(ea_list->ea.name)) {
			return true;
		}
	}
	return false;
}
Example #13
0
static NTSTATUS store_acl_blob_pathname(vfs_handle_struct *handle,
					const char *fname,
					DATA_BLOB *pblob)
{
	uint8 id_buf[16];
	struct file_id id;
	TDB_DATA data;
	SMB_STRUCT_STAT sbuf;
	struct db_context *db;
	struct db_record *rec;
	int ret = -1;

	DEBUG(10,("store_acl_blob_pathname: storing blob "
			"length %u on file %s\n",
			(unsigned int)pblob->length, fname));

	SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context,
		return NT_STATUS_INTERNAL_DB_CORRUPTION);

	if (lp_posix_pathnames()) {
		ret = SMB_VFS_LSTAT(handle->conn, fname, &sbuf);
	} else {
		ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
	}

	if (ret == -1) {
		return map_nt_error_from_unix(errno);
	}

	id = vfs_file_id_from_sbuf(handle->conn, &sbuf);

	/* For backwards compatibility only store the dev/inode. */
	push_file_id_16((char *)id_buf, &id);

	rec = db->fetch_locked(db, talloc_tos(),
				make_tdb_data(id_buf,
					sizeof(id_buf)));
	if (rec == NULL) {
		DEBUG(0, ("store_acl_blob_pathname_tdb: fetch_lock failed\n"));
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}
	data.dptr = pblob->data;
	data.dsize = pblob->length;
	return rec->store(rec, data, 0);
}
Example #14
0
NTSTATUS unix_convert(TALLOC_CTX *ctx,
			connection_struct *conn,
			const char *orig_path,
			bool allow_wcard_last_component,
			char **pp_conv_path,
			char **pp_saved_last_component,
			SMB_STRUCT_STAT *pst)
{
	SMB_STRUCT_STAT st;
	char *start, *end;
	char *dirpath = NULL;
	char *name = NULL;
	char *stream = NULL;
	bool component_was_mangled = False;
	bool name_has_wildcard = False;
	bool posix_pathnames = false;
	NTSTATUS result;
	int ret = -1;

	SET_STAT_INVALID(*pst);
	*pp_conv_path = NULL;
	if(pp_saved_last_component) {
		*pp_saved_last_component = NULL;
	}

	if (conn->printer) {
		/* we don't ever use the filenames on a printer share as a
			filename - so don't convert them */
		if (!(*pp_conv_path = talloc_strdup(ctx,orig_path))) {
			return NT_STATUS_NO_MEMORY;
		}
		return NT_STATUS_OK;
	}

	DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path));

	/*
	 * Conversion to basic unix format is already done in
	 * check_path_syntax().
	 */

	/*
	 * Names must be relative to the root of the service - any leading /.
	 * and trailing /'s should have been trimmed by check_path_syntax().
	 */

#ifdef DEVELOPER
	SMB_ASSERT(*orig_path != '/');
#endif

	/*
	 * If we trimmed down to a single '\0' character
	 * then we should use the "." directory to avoid
	 * searching the cache, but not if we are in a
	 * printing share.
	 * As we know this is valid we can return true here.
	 */

	if (!*orig_path) {
		if (!(name = talloc_strdup(ctx,"."))) {
			return NT_STATUS_NO_MEMORY;
		}
		if (SMB_VFS_STAT(conn,name,&st) == 0) {
			*pst = st;
		} else {
			return map_nt_error_from_unix(errno);
		}
		DEBUG(5,("conversion finished \"\" -> %s\n",name));
		goto done;
	}

	if (orig_path[0] == '.' && (orig_path[1] == '/' ||
				orig_path[1] == '\0')) {
		/* Start of pathname can't be "." only. */
		if (orig_path[1] == '\0' || orig_path[2] == '\0') {
			result = NT_STATUS_OBJECT_NAME_INVALID;
		} else {
			result =determine_path_error(
				&orig_path[2], allow_wcard_last_component);
		}
		return result;
	}

	if (!(name = talloc_strdup(ctx, orig_path))) {
		DEBUG(0, ("talloc_strdup failed\n"));
		return NT_STATUS_NO_MEMORY;
	}

	/*
	 * Large directory fix normalization. If we're case sensitive, and
	 * the case preserving parameters are set to "no", normalize the case of
	 * the incoming filename from the client WHETHER IT EXISTS OR NOT !
	 * This is in conflict with the current (3.0.20) man page, but is
	 * what people expect from the "large directory howto". I'll update
	 * the man page. Thanks to [email protected] for finding this. JRA.
	 */

	if (conn->case_sensitive && !conn->case_preserve &&
			!conn->short_case_preserve) {
		strnorm(name, lp_defaultcase(SNUM(conn)));
	}

	/*
	 * Ensure saved_last_component is valid even if file exists.
	 */

	if(pp_saved_last_component) {
		end = strrchr_m(name, '/');
		if (end) {
			*pp_saved_last_component = talloc_strdup(ctx, end + 1);
		} else {
			*pp_saved_last_component = talloc_strdup(ctx,
							name);
		}
	}

	posix_pathnames = lp_posix_pathnames();

	if (!posix_pathnames) {
		stream = strchr_m(name, ':');

		if (stream != NULL) {
			char *tmp = talloc_strdup(ctx, stream);
			if (tmp == NULL) {
				TALLOC_FREE(name);
				return NT_STATUS_NO_MEMORY;
			}
			*stream = '\0';
			stream = tmp;
		}
	}

	start = name;

	/* If we're providing case insentive semantics or
	 * the underlying filesystem is case insensitive,
	 * then a case-normalized hit in the stat-cache is
	 * authoratitive. JRA.
	 */

	if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) &&
			stat_cache_lookup(conn, &name, &dirpath, &start, &st)) {
		*pst = st;
		goto done;
	}

	/*
	 * Make sure "dirpath" is an allocated string, we use this for
	 * building the directories with asprintf and free it.
	 */

	if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) {
		DEBUG(0, ("talloc_strdup failed\n"));
		TALLOC_FREE(name);
		return NT_STATUS_NO_MEMORY;
	}

	/*
	 * stat the name - if it exists then we are all done!
	 */

	if (posix_pathnames) {
		ret = SMB_VFS_LSTAT(conn,name,&st);
	} else {
		ret = SMB_VFS_STAT(conn,name,&st);
	}

	if (ret == 0) {
		/* Ensure we catch all names with in "/."
		   this is disallowed under Windows. */
		const char *p = strstr(name, "/."); /* mb safe. */
		if (p) {
			if (p[2] == '/') {
				/* Error code within a pathname. */
				result = NT_STATUS_OBJECT_PATH_NOT_FOUND;
				goto fail;
			} else if (p[2] == '\0') {
				/* Error code at the end of a pathname. */
				result = NT_STATUS_OBJECT_NAME_INVALID;
				goto fail;
			}
		}
		stat_cache_add(orig_path, name, conn->case_sensitive);
		DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
		*pst = st;
		goto done;
	}

	DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
				name, dirpath, start));

	/*
	 * A special case - if we don't have any mangling chars and are case
	 * sensitive or the underlying filesystem is case insentive then searching
	 * won't help.
	 */

	if ((conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) &&
			!mangle_is_mangled(name, conn->params)) {
		goto done;
	}

	/*
	 * is_mangled() was changed to look at an entire pathname, not
	 * just a component. JRA.
	 */

	if (mangle_is_mangled(start, conn->params)) {
		component_was_mangled = True;
	}

	/*
	 * Now we need to recursively match the name against the real
	 * directory structure.
	 */

	/*
	 * Match each part of the path name separately, trying the names
	 * as is first, then trying to scan the directory for matching names.
	 */

	for (; start ; start = (end?end+1:(char *)NULL)) {
		/*
		 * Pinpoint the end of this section of the filename.
		 */
		/* mb safe. '/' can't be in any encoded char. */
		end = strchr(start, '/');

		/*
		 * Chop the name at this point.
		 */
		if (end) {
			*end = 0;
		}

		if (pp_saved_last_component) {
			TALLOC_FREE(*pp_saved_last_component);
			*pp_saved_last_component = talloc_strdup(ctx,
							end ? end + 1 : start);
			if (!*pp_saved_last_component) {
				DEBUG(0, ("talloc failed\n"));
				return NT_STATUS_NO_MEMORY;
			}
		}

		/* The name cannot have a component of "." */

		if (ISDOT(start)) {
			if (!end)  {
				/* Error code at the end of a pathname. */
				result = NT_STATUS_OBJECT_NAME_INVALID;
			} else {
				result = determine_path_error(end+1,
						allow_wcard_last_component);
			}
			goto fail;
		}

		/* The name cannot have a wildcard if it's not
		   the last component. */

		name_has_wildcard = ms_has_wild(start);

		/* Wildcard not valid anywhere. */
		if (name_has_wildcard && !allow_wcard_last_component) {
			result = NT_STATUS_OBJECT_NAME_INVALID;
			goto fail;
		}

		/* Wildcards never valid within a pathname. */
		if (name_has_wildcard && end) {
			result = NT_STATUS_OBJECT_NAME_INVALID;
			goto fail;
		}

		/*
		 * Check if the name exists up to this point.
		 */

		if (posix_pathnames) {
			ret = SMB_VFS_LSTAT(conn,name, &st);
		} else {
			ret = SMB_VFS_STAT(conn,name, &st);
		}

		if (ret == 0) {
			/*
			 * It exists. it must either be a directory or this must
			 * be the last part of the path for it to be OK.
			 */
			if (end && !(st.st_mode & S_IFDIR)) {
				/*
				 * An intermediate part of the name isn't
				 * a directory.
				 */
				DEBUG(5,("Not a dir %s\n",start));
				*end = '/';
				/*
				 * We need to return the fact that the
				 * intermediate name resolution failed. This
				 * is used to return an error of ERRbadpath
				 * rather than ERRbadfile. Some Windows
				 * applications depend on the difference between
				 * these two errors.
				 */
				result = NT_STATUS_OBJECT_PATH_NOT_FOUND;
				goto fail;
			}

			if (!end) {
				/*
				 * We just scanned for, and found the end of
				 * the path. We must return the valid stat
				 * struct. JRA.
				 */

				*pst = st;
			}

		} else {
			char *found_name = NULL;

			/* Stat failed - ensure we don't use it. */
			SET_STAT_INVALID(st);

			/*
			 * Reset errno so we can detect
			 * directory open errors.
			 */
			errno = 0;

			/*
			 * Try to find this part of the path in the directory.
			 */

			if (name_has_wildcard ||
			    (get_real_filename_mangled(
				     conn, dirpath, start,
				     talloc_tos(), &found_name) == -1)) {
				char *unmangled;

				if (end) {
					/*
					 * An intermediate part of the name
					 * can't be found.
					 */
					DEBUG(5,("Intermediate not found %s\n",
							start));
					*end = '/';

					/*
					 * We need to return the fact that the
					 * intermediate name resolution failed.
					 * This is used to return an error of
					 * ERRbadpath rather than ERRbadfile.
					 * Some Windows applications depend on
					 * the difference between these two
					 * errors.
					 */

					/*
					 * ENOENT, ENOTDIR and ELOOP all map
					 * to NT_STATUS_OBJECT_PATH_NOT_FOUND
					 * in the filename walk.
					 */

					if (errno == ENOENT ||
							errno == ENOTDIR ||
							errno == ELOOP) {
						result =
						NT_STATUS_OBJECT_PATH_NOT_FOUND;
					}
					else {
						result =
						map_nt_error_from_unix(errno);
					}
					goto fail;
				}

				/* ENOENT is the only valid error here. */
				if ((errno != 0) && (errno != ENOENT)) {
					/*
					 * ENOTDIR and ELOOP both map to
					 * NT_STATUS_OBJECT_PATH_NOT_FOUND
					 * in the filename walk.
					 */
					if (errno == ENOTDIR ||
							errno == ELOOP) {
						result =
						NT_STATUS_OBJECT_PATH_NOT_FOUND;
					}
					else {
						result =
						map_nt_error_from_unix(errno);
					}
					goto fail;
				}

				/*
				 * Just the last part of the name doesn't exist.
				 * We need to strupper() or strlower() it as
				 * this conversion may be used for file creation
				 * purposes. Fix inspired by
				 * Thomas Neumann <*****@*****.**>.
				 */
				if (!conn->case_preserve ||
				    (mangle_is_8_3(start, False,
						   conn->params) &&
						 !conn->short_case_preserve)) {
					strnorm(start,
						lp_defaultcase(SNUM(conn)));
				}

				/*
				 * check on the mangled stack to see if we can
				 * recover the base of the filename.
				 */

				if (mangle_is_mangled(start, conn->params)
				    && mangle_lookup_name_from_8_3(ctx,
					    		start,
							&unmangled,
							conn->params)) {
					char *tmp;
					size_t start_ofs = start - name;

					if (*dirpath != '\0') {
						tmp = talloc_asprintf(ctx,
							"%s/%s", dirpath,
							unmangled);
						TALLOC_FREE(unmangled);
					}
					else {
						tmp = unmangled;
					}
					if (tmp == NULL) {
						DEBUG(0, ("talloc failed\n"));
						return NT_STATUS_NO_MEMORY;
					}
					TALLOC_FREE(name);
					name = tmp;
					start = name + start_ofs;
					end = start + strlen(start);
				}

				DEBUG(5,("New file %s\n",start));
				goto done;
			}


			/*
			 * Restore the rest of the string. If the string was
			 * mangled the size may have changed.
			 */
			if (end) {
				char *tmp;
				size_t start_ofs = start - name;

				if (*dirpath != '\0') {
					tmp = talloc_asprintf(ctx,
						"%s/%s/%s", dirpath,
						found_name, end+1);
				}
				else {
					tmp = talloc_asprintf(ctx,
						"%s/%s", found_name,
						end+1);
				}
				if (tmp == NULL) {
					DEBUG(0, ("talloc_asprintf failed\n"));
					return NT_STATUS_NO_MEMORY;
				}
				TALLOC_FREE(name);
				name = tmp;
				start = name + start_ofs;
				end = start + strlen(found_name);
				*end = '\0';
			} else {
				char *tmp;
				size_t start_ofs = start - name;

				if (*dirpath != '\0') {
					tmp = talloc_asprintf(ctx,
						"%s/%s", dirpath,
						found_name);
				} else {
					tmp = talloc_strdup(ctx,
						found_name);
				}
				if (tmp == NULL) {
					DEBUG(0, ("talloc failed\n"));
					return NT_STATUS_NO_MEMORY;
				}
				TALLOC_FREE(name);
				name = tmp;
				start = name + start_ofs;

				/*
				 * We just scanned for, and found the end of
				 * the path. We must return a valid stat struct
				 * if it exists. JRA.
				 */

				if (posix_pathnames) {
					ret = SMB_VFS_LSTAT(conn,name, &st);
				} else {
					ret = SMB_VFS_STAT(conn,name, &st);
				}

				if (ret == 0) {
					*pst = st;
				} else {
					SET_STAT_INVALID(st);
				}
			}

			TALLOC_FREE(found_name);
		} /* end else */

#ifdef DEVELOPER
		/*
		 * This sucks!
		 * We should never provide different behaviors
		 * depending on DEVELOPER!!!
		 */
		if (VALID_STAT(st)) {
			bool delete_pending;
			get_file_infos(vfs_file_id_from_sbuf(conn, &st),
				       &delete_pending, NULL);
			if (delete_pending) {
				result = NT_STATUS_DELETE_PENDING;
				goto fail;
			}
		}
#endif

		/*
		 * Add to the dirpath that we have resolved so far.
		 */

		if (*dirpath != '\0') {
			char *tmp = talloc_asprintf(ctx,
					"%s/%s", dirpath, start);
			if (!tmp) {
				DEBUG(0, ("talloc_asprintf failed\n"));
				return NT_STATUS_NO_MEMORY;
			}
			TALLOC_FREE(dirpath);
			dirpath = tmp;
		}
		else {
			TALLOC_FREE(dirpath);
			if (!(dirpath = talloc_strdup(ctx,start))) {
				DEBUG(0, ("talloc_strdup failed\n"));
				return NT_STATUS_NO_MEMORY;
			}
		}

		/*
		 * Don't cache a name with mangled or wildcard components
		 * as this can change the size.
		 */

		if(!component_was_mangled && !name_has_wildcard) {
			stat_cache_add(orig_path, dirpath,
					conn->case_sensitive);
		}

		/*
		 * Restore the / that we wiped out earlier.
		 */
		if (end) {
			*end = '/';
		}
	}

	/*
	 * Don't cache a name with mangled or wildcard components
	 * as this can change the size.
	 */

	if(!component_was_mangled && !name_has_wildcard) {
		stat_cache_add(orig_path, name, conn->case_sensitive);
	}

	/*
	 * The name has been resolved.
	 */

	DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));

 done:
	if (stream != NULL) {
		char *tmp = NULL;

		result = build_stream_path(ctx, conn, orig_path, name, stream,
					   pst, &tmp);
		if (!NT_STATUS_IS_OK(result)) {
			goto fail;
		}

		DEBUG(10, ("build_stream_path returned %s\n", tmp));

		TALLOC_FREE(name);
		name = tmp;
	}
	*pp_conv_path = name;
	TALLOC_FREE(dirpath);
	return NT_STATUS_OK;
 fail:
	DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start));
	if (*dirpath != '\0') {
		*pp_conv_path = talloc_asprintf(ctx,
				"%s/%s", dirpath, start);
	} else {
		*pp_conv_path = talloc_strdup(ctx, start);
	}
	if (!*pp_conv_path) {
		DEBUG(0, ("talloc_asprintf failed\n"));
		return NT_STATUS_NO_MEMORY;
	}
	TALLOC_FREE(name);
	TALLOC_FREE(dirpath);
	return result;
}
Example #15
0
int hpuxacl_sys_acl_set_file(vfs_handle_struct *handle,
			     const char *name,
			     SMB_ACL_TYPE_T type,
			     SMB_ACL_T theacl)
{
	int ret = -1;
	HPUX_ACL_T hpux_acl = NULL;
	int count;
	struct smb_filename *smb_fname = NULL;
	NTSTATUS status;

	DEBUG(10, ("hpuxacl_sys_acl_set_file called for file '%s'\n",
		   name));

	status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
					    &smb_fname);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	if(hpux_acl_call_present() == False) {
		/* Looks like we don't have the acl() system call on HPUX. 
		 * May be the system doesn't have the latest version of JFS.
		 */
		goto done;
	}

	if ((type != SMB_ACL_TYPE_ACCESS) && (type != SMB_ACL_TYPE_DEFAULT)) {
		errno = EINVAL;
		DEBUG(10, ("invalid smb acl type given (%d).\n", type));
		goto done;
	}
	DEBUGADD(10, ("setting %s acl\n", 
		      ((type == SMB_ACL_TYPE_ACCESS) ? "access" : "default")));

	if(!smb_acl_to_hpux_acl(theacl, &hpux_acl, &count, type)) {
		DEBUG(10, ("conversion smb_acl -> hpux_acl failed (%s).\n",
			   strerror(errno)));
                goto done;
	}

	/*
	 * if the file is a directory, there is extra work to do:
	 * since the hpux acl call stores both the access acl and 
	 * the default acl as provided, we have to get the acl part 
	 * that has _not_ been specified in "type" from the file first 
	 * and concatenate it with the acl provided.
	 */
	if (lp_posix_pathnames()) {
		ret = SMB_VFS_LSTAT(handle->conn, smb_fname);
	} else {
		ret = SMB_VFS_STAT(handle->conn, smb_fname);
	}
	if (ret != 0) {
		DEBUG(10, ("Error in stat call: %s\n", strerror(errno)));
		goto done;
	}
	if (S_ISDIR(smb_fname->st.st_ex_mode)) {
		HPUX_ACL_T other_acl; 
		int other_count;
		SMB_ACL_TYPE_T other_type;

		other_type = (type == SMB_ACL_TYPE_ACCESS) 
			? SMB_ACL_TYPE_DEFAULT
			: SMB_ACL_TYPE_ACCESS;
		DEBUGADD(10, ("getting acl from filesystem\n"));
		if (!hpux_acl_get_file(smb_fname->base_name, &other_acl,
				       &other_count)) {
			DEBUG(10, ("error getting acl from directory\n"));
			goto done;
		}
		DEBUG(10, ("adding %s part of fs acl to given acl\n",
			   ((other_type == SMB_ACL_TYPE_ACCESS) 
			    ? "access"
			    : "default")));
		if (!hpux_add_to_acl(&hpux_acl, &count, other_acl,
					other_count, other_type)) 
		{
			DEBUG(10, ("error adding other acl.\n"));
			SAFE_FREE(other_acl);
			goto done;
		}
		SAFE_FREE(other_acl);
	}
	else if (type != SMB_ACL_TYPE_ACCESS) {
		errno = EINVAL;
		goto done;
	}

	if (!hpux_acl_sort(hpux_acl, count)) {
		DEBUG(10, ("resulting acl is not valid!\n"));
		goto done;
	}
	DEBUG(10, ("resulting acl is valid.\n"));

	ret = acl(discard_const_p(char, smb_fname->base_name), ACL_SET, count,
		  hpux_acl);
	if (ret != 0) {
		DEBUG(0, ("ERROR calling acl: %s\n", strerror(errno)));
	}

 done:
	DEBUG(10, ("hpuxacl_sys_acl_set_file %s.\n",
		   ((ret != 0) ? "failed" : "succeeded")));
	TALLOC_FREE(smb_fname);
	SAFE_FREE(hpux_acl);
	return ret;
}
Example #16
0
static NTSTATUS parse_dfs_path(connection_struct *conn,
				const char *pathname,
				bool allow_wcards,
				bool allow_broken_path,
				struct dfs_path *pdp, /* MUST BE TALLOCED */
				bool *ppath_contains_wcard)
{
	char *pathname_local;
	char *p,*temp;
	char *servicename;
	char *eos_ptr;
	NTSTATUS status = NT_STATUS_OK;
	char sepchar;

	ZERO_STRUCTP(pdp);

	/*
	 * This is the only talloc we should need to do
	 * on the struct dfs_path. All the pointers inside
	 * it should point to offsets within this string.
	 */

	pathname_local = talloc_strdup(pdp, pathname);
	if (!pathname_local) {
		return NT_STATUS_NO_MEMORY;
	}
	/* Get a pointer to the terminating '\0' */
	eos_ptr = &pathname_local[strlen(pathname_local)];
	p = temp = pathname_local;

	pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');

	sepchar = pdp->posix_path ? '/' : '\\';

	if (allow_broken_path && (*pathname != sepchar)) {
		DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
			pathname, sepchar ));
		/*
		 * Possibly client sent a local path by mistake.
		 * Try and convert to a local path.
		 */

		pdp->hostname = eos_ptr; /* "" */
		pdp->servicename = eos_ptr; /* "" */

		/* We've got no info about separators. */
		pdp->posix_path = lp_posix_pathnames();
		p = temp;
		DEBUG(10,("parse_dfs_path: trying to convert %s to a "
			"local path\n",
			temp));
		goto local_path;
	}

	/*
	 * Safe to use on talloc'ed string as it only shrinks.
	 * It also doesn't affect the eos_ptr.
	 */
	trim_char(temp,sepchar,sepchar);

	DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
		temp, sepchar));

	/* Now tokenize. */
	/* Parse out hostname. */
	p = strchr_m(temp,sepchar);
	if(p == NULL) {
		DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
			temp));
		/*
		 * Possibly client sent a local path by mistake.
		 * Try and convert to a local path.
		 */

		pdp->hostname = eos_ptr; /* "" */
		pdp->servicename = eos_ptr; /* "" */

		p = temp;
		DEBUG(10,("parse_dfs_path: trying to convert %s "
			"to a local path\n",
			temp));
		goto local_path;
	}
	*p = '\0';
	pdp->hostname = temp;

	DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));

	/* Parse out servicename. */
	servicename = p+1;
	p = strchr_m(servicename,sepchar);
	if (p) {
		*p = '\0';
	}

	/* Is this really our servicename ? */
	if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn)))
			|| (strequal(servicename, HOMES_NAME)
			&& strequal(lp_servicename(talloc_tos(), SNUM(conn)),
				get_current_username()) )) ) {
		DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
			servicename));

		/*
		 * Possibly client sent a local path by mistake.
		 * Try and convert to a local path.
		 */

		pdp->hostname = eos_ptr; /* "" */
		pdp->servicename = eos_ptr; /* "" */

		/* Repair the path - replace the sepchar's
		   we nulled out */
		servicename--;
		*servicename = sepchar;
		if (p) {
			*p = sepchar;
		}

		p = temp;
		DEBUG(10,("parse_dfs_path: trying to convert %s "
			"to a local path\n",
			temp));
		goto local_path;
	}

	pdp->servicename = servicename;

	DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));

	if(p == NULL) {
		/* Client sent self referral \server\share. */
		pdp->reqpath = eos_ptr; /* "" */
		return NT_STATUS_OK;
	}

	p++;

  local_path:

	*ppath_contains_wcard = False;

	pdp->reqpath = p;

	/* Rest is reqpath. */
	if (pdp->posix_path) {
		status = check_path_syntax_posix(pdp->reqpath);
	} else {
		if (allow_wcards) {
			status = check_path_syntax_wcard(pdp->reqpath,
					ppath_contains_wcard);
		} else {
			status = check_path_syntax(pdp->reqpath);
		}
	}

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
			p, nt_errstr(status) ));
		return status;
	}

	DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
	return NT_STATUS_OK;
}
Example #17
0
NTSTATUS unix_convert(TALLOC_CTX *ctx,
		      connection_struct *conn,
		      const char *orig_path,
		      struct smb_filename **smb_fname_out,
		      uint32_t ucf_flags)
{
	struct smb_filename *smb_fname = NULL;
	char *start, *end;
	char *dirpath = NULL;
	char *stream = NULL;
	bool component_was_mangled = False;
	bool name_has_wildcard = False;
	bool posix_pathnames = false;
	bool allow_wcard_last_component =
	    (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP);
	bool save_last_component = ucf_flags & UCF_SAVE_LCOMP;
	NTSTATUS status;
	int ret = -1;

	*smb_fname_out = NULL;

	smb_fname = talloc_zero(ctx, struct smb_filename);
	if (smb_fname == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	if (conn->printer) {
		/* we don't ever use the filenames on a printer share as a
			filename - so don't convert them */
		if (!(smb_fname->base_name = talloc_strdup(smb_fname,
							   orig_path))) {
			status = NT_STATUS_NO_MEMORY;
			goto err;
		}
		goto done;
	}

	DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path));

	/*
	 * Conversion to basic unix format is already done in
	 * check_path_syntax().
	 */

	/*
	 * Names must be relative to the root of the service - any leading /.
	 * and trailing /'s should have been trimmed by check_path_syntax().
	 */

#ifdef DEVELOPER
	SMB_ASSERT(*orig_path != '/');
#endif

	/*
	 * If we trimmed down to a single '\0' character
	 * then we should use the "." directory to avoid
	 * searching the cache, but not if we are in a
	 * printing share.
	 * As we know this is valid we can return true here.
	 */

	if (!*orig_path) {
		if (!(smb_fname->base_name = talloc_strdup(smb_fname, "."))) {
			status = NT_STATUS_NO_MEMORY;
			goto err;
		}
		if (SMB_VFS_STAT(conn, smb_fname) != 0) {
			status = map_nt_error_from_unix(errno);
			goto err;
		}
		DEBUG(5, ("conversion finished \"\" -> %s\n",
			  smb_fname->base_name));
		goto done;
	}

	if (orig_path[0] == '.' && (orig_path[1] == '/' ||
				orig_path[1] == '\0')) {
		/* Start of pathname can't be "." only. */
		if (orig_path[1] == '\0' || orig_path[2] == '\0') {
			status = NT_STATUS_OBJECT_NAME_INVALID;
		} else {
			status =determine_path_error(&orig_path[2],
			    allow_wcard_last_component);
		}
		goto err;
	}

	/* Start with the full orig_path as given by the caller. */
	if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) {
		DEBUG(0, ("talloc_strdup failed\n"));
		status = NT_STATUS_NO_MEMORY;
		goto err;
	}

	/*
	 * Large directory fix normalization. If we're case sensitive, and
	 * the case preserving parameters are set to "no", normalize the case of
	 * the incoming filename from the client WHETHER IT EXISTS OR NOT !
	 * This is in conflict with the current (3.0.20) man page, but is
	 * what people expect from the "large directory howto". I'll update
	 * the man page. Thanks to [email protected] for finding this. JRA.
	 */

	if (conn->case_sensitive && !conn->case_preserve &&
			!conn->short_case_preserve) {
		strnorm(smb_fname->base_name, lp_defaultcase(SNUM(conn)));
	}

	/*
	 * Ensure saved_last_component is valid even if file exists.
	 */

	if(save_last_component) {
		end = strrchr_m(smb_fname->base_name, '/');
		if (end) {
			smb_fname->original_lcomp = talloc_strdup(smb_fname,
								  end + 1);
		} else {
			smb_fname->original_lcomp =
			    talloc_strdup(smb_fname, smb_fname->base_name);
		}
		if (smb_fname->original_lcomp == NULL) {
			status = NT_STATUS_NO_MEMORY;
			goto err;
		}
	}

	posix_pathnames = (lp_posix_pathnames() ||
				(ucf_flags & UCF_POSIX_PATHNAMES));

	/*
	 * Strip off the stream, and add it back when we're done with the
	 * base_name.
	 */
	if (!posix_pathnames) {
		stream = strchr_m(smb_fname->base_name, ':');

		if (stream != NULL) {
			char *tmp = talloc_strdup(smb_fname, stream);
			if (tmp == NULL) {
				status = NT_STATUS_NO_MEMORY;
				goto err;
			}
			/*
			 * Since this is actually pointing into
			 * smb_fname->base_name this truncates base_name.
			 */
			*stream = '\0';
			stream = tmp;
		}
	}

	start = smb_fname->base_name;

	/*
	 * If we're providing case insensitive semantics or
	 * the underlying filesystem is case insensitive,
	 * then a case-normalized hit in the stat-cache is
	 * authoratitive. JRA.
	 *
	 * Note: We're only checking base_name.  The stream_name will be
	 * added and verified in build_stream_path().
	 */

	if((!conn->case_sensitive || !(conn->fs_capabilities &
				       FILE_CASE_SENSITIVE_SEARCH)) &&
	    stat_cache_lookup(conn, posix_pathnames, &smb_fname->base_name, &dirpath, &start,
			      &smb_fname->st)) {
		goto done;
	}

	/*
	 * Make sure "dirpath" is an allocated string, we use this for
	 * building the directories with talloc_asprintf and free it.
	 */

	if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) {
		DEBUG(0, ("talloc_strdup failed\n"));
		status = NT_STATUS_NO_MEMORY;
		goto err;
	}

	/*
	 * If we have a wildcard we must walk the path to
	 * find where the error is, even if case sensitive
	 * is true.
	 */

	name_has_wildcard = ms_has_wild(smb_fname->base_name);
	if (name_has_wildcard && !allow_wcard_last_component) {
		/* Wildcard not valid anywhere. */
		status = NT_STATUS_OBJECT_NAME_INVALID;
		goto fail;
	}

	DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
		 smb_fname->base_name, dirpath, start));

	if (!name_has_wildcard) {
		/*
		 * stat the name - if it exists then we can add the stream back (if
		 * there was one) and be done!
		 */

		if (posix_pathnames) {
			ret = SMB_VFS_LSTAT(conn, smb_fname);
		} else {
			ret = SMB_VFS_STAT(conn, smb_fname);
		}

		if (ret == 0) {
			status = check_for_dot_component(smb_fname);
			if (!NT_STATUS_IS_OK(status)) {
				goto fail;
			}
			/* Add the path (not including the stream) to the cache. */
			stat_cache_add(orig_path, smb_fname->base_name,
				       conn->case_sensitive);
			DEBUG(5,("conversion of base_name finished %s -> %s\n",
				 orig_path, smb_fname->base_name));
			goto done;
		}

		/* Stat failed - ensure we don't use it. */
		SET_STAT_INVALID(smb_fname->st);

		if (errno == ENOENT) {
			/* Optimization when creating a new file - only
			   the last component doesn't exist. */
			status = check_parent_exists(ctx,
						conn,
						posix_pathnames,
						smb_fname,
						&dirpath,
						&start);
			if (!NT_STATUS_IS_OK(status)) {
				goto fail;
			}
		}

		/*
		 * A special case - if we don't have any wildcards or mangling chars and are case
		 * sensitive or the underlying filesystem is case insensitive then searching
		 * won't help.
		 */

		if ((conn->case_sensitive || !(conn->fs_capabilities &
					FILE_CASE_SENSITIVE_SEARCH)) &&
				!mangle_is_mangled(smb_fname->base_name, conn->params)) {

			status = check_for_dot_component(smb_fname);
			if (!NT_STATUS_IS_OK(status)) {
				goto fail;
			}

			/*
			 * The stat failed. Could be ok as it could be
 			 * a new file.
 			 */

			if (errno == ENOTDIR || errno == ELOOP) {
				status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
				goto fail;
			} else if (errno == ENOENT) {
				/*
				 * Was it a missing last component ?
				 * or a missing intermediate component ?
				 */
				struct smb_filename parent_fname;
				const char *last_component = NULL;

				ZERO_STRUCT(parent_fname);
				if (!parent_dirname(ctx, smb_fname->base_name,
							&parent_fname.base_name,
							&last_component)) {
					status = NT_STATUS_NO_MEMORY;
					goto fail;
				}
				if (posix_pathnames) {
					ret = SMB_VFS_LSTAT(conn, &parent_fname);
				} else {
					ret = SMB_VFS_STAT(conn, &parent_fname);
				}
				if (ret == -1) {
					if (errno == ENOTDIR ||
							errno == ENOENT ||
							errno == ELOOP) {
						status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
						goto fail;
					}
				}

				/*
				 * Missing last component is ok - new file.
				 * Also deal with permission denied elsewhere.
				 * Just drop out to done.
				 */
				goto done;
			}
		}
	} else {
		/*
		 * We have a wildcard in the pathname.
		 *
		 * Optimization for common case where the wildcard
		 * is in the last component and the client already
		 * sent the correct case.
		 */
		status = check_parent_exists(ctx,
					conn,
					posix_pathnames,
					smb_fname,
					&dirpath,
					&start);
		if (!NT_STATUS_IS_OK(status)) {
			goto fail;
		}
	}

	/*
	 * is_mangled() was changed to look at an entire pathname, not
	 * just a component. JRA.
	 */

	if (mangle_is_mangled(start, conn->params)) {
		component_was_mangled = True;
	}

	/*
	 * Now we need to recursively match the name against the real
	 * directory structure.
	 */

	/*
	 * Match each part of the path name separately, trying the names
	 * as is first, then trying to scan the directory for matching names.
	 */

	for (; start ; start = (end?end+1:(char *)NULL)) {
		/*
		 * Pinpoint the end of this section of the filename.
		 */
		/* mb safe. '/' can't be in any encoded char. */
		end = strchr(start, '/');

		/*
		 * Chop the name at this point.
		 */
		if (end) {
			*end = 0;
		}

		if (save_last_component) {
			TALLOC_FREE(smb_fname->original_lcomp);
			smb_fname->original_lcomp = talloc_strdup(smb_fname,
							end ? end + 1 : start);
			if (!smb_fname->original_lcomp) {
				DEBUG(0, ("talloc failed\n"));
				status = NT_STATUS_NO_MEMORY;
				goto err;
			}
		}

		/* The name cannot have a component of "." */

		if (ISDOT(start)) {
			if (!end)  {
				/* Error code at the end of a pathname. */
				status = NT_STATUS_OBJECT_NAME_INVALID;
			} else {
				status = determine_path_error(end+1,
						allow_wcard_last_component);
			}
			goto fail;
		}

		/* The name cannot have a wildcard if it's not
		   the last component. */

		name_has_wildcard = ms_has_wild(start);

		/* Wildcards never valid within a pathname. */
		if (name_has_wildcard && end) {
			status = NT_STATUS_OBJECT_NAME_INVALID;
			goto fail;
		}

		/* Skip the stat call if it's a wildcard end. */
		if (name_has_wildcard) {
			DEBUG(5,("Wildcard %s\n",start));
			goto done;
		}

		/*
		 * Check if the name exists up to this point.
		 */

		if (posix_pathnames) {
			ret = SMB_VFS_LSTAT(conn, smb_fname);
		} else {
			ret = SMB_VFS_STAT(conn, smb_fname);
		}

		if (ret == 0) {
			/*
			 * It exists. it must either be a directory or this must
			 * be the last part of the path for it to be OK.
			 */
			if (end && !S_ISDIR(smb_fname->st.st_ex_mode)) {
				/*
				 * An intermediate part of the name isn't
				 * a directory.
				 */
				DEBUG(5,("Not a dir %s\n",start));
				*end = '/';
				/*
				 * We need to return the fact that the
				 * intermediate name resolution failed. This
				 * is used to return an error of ERRbadpath
				 * rather than ERRbadfile. Some Windows
				 * applications depend on the difference between
				 * these two errors.
				 */
				status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
				goto fail;
			}

		} else {
			char *found_name = NULL;

			/* Stat failed - ensure we don't use it. */
			SET_STAT_INVALID(smb_fname->st);

			/*
			 * Reset errno so we can detect
			 * directory open errors.
			 */
			errno = 0;

			/*
			 * Try to find this part of the path in the directory.
			 */

			if (name_has_wildcard ||
			    (get_real_filename(conn, dirpath, start,
					       talloc_tos(),
					       &found_name) == -1)) {
				char *unmangled;

				if (end) {
					/*
					 * An intermediate part of the name
					 * can't be found.
					 */
					DEBUG(5,("Intermediate not found %s\n",
							start));
					*end = '/';

					/*
					 * We need to return the fact that the
					 * intermediate name resolution failed.
					 * This is used to return an error of
					 * ERRbadpath rather than ERRbadfile.
					 * Some Windows applications depend on
					 * the difference between these two
					 * errors.
					 */

					/*
					 * ENOENT, ENOTDIR and ELOOP all map
					 * to NT_STATUS_OBJECT_PATH_NOT_FOUND
					 * in the filename walk.
					 */

					if (errno == ENOENT ||
							errno == ENOTDIR ||
							errno == ELOOP) {
						status =
						NT_STATUS_OBJECT_PATH_NOT_FOUND;
					}
					else {
						status =
						map_nt_error_from_unix(errno);
					}
					goto fail;
				}

				/*
				 * ENOENT/EACCESS are the only valid errors
				 * here. EACCESS needs handling here for
				 * "dropboxes", i.e. directories where users
				 * can only put stuff with permission -wx.
				 */
				if ((errno != 0) && (errno != ENOENT)
				    && (errno != EACCES)) {
					/*
					 * ENOTDIR and ELOOP both map to
					 * NT_STATUS_OBJECT_PATH_NOT_FOUND
					 * in the filename walk.
					 */
					if (errno == ENOTDIR ||
							errno == ELOOP) {
						status =
						NT_STATUS_OBJECT_PATH_NOT_FOUND;
					} else {
						status =
						map_nt_error_from_unix(errno);
					}
					goto fail;
				}

				/*
				 * Just the last part of the name doesn't exist.
				 * We need to strupper() or strlower() it as
				 * this conversion may be used for file creation
				 * purposes. Fix inspired by
				 * Thomas Neumann <*****@*****.**>.
				 */
				if (!conn->case_preserve ||
				    (mangle_is_8_3(start, False,
						   conn->params) &&
						 !conn->short_case_preserve)) {
					strnorm(start,
						lp_defaultcase(SNUM(conn)));
				}

				/*
				 * check on the mangled stack to see if we can
				 * recover the base of the filename.
				 */

				if (mangle_is_mangled(start, conn->params)
				    && mangle_lookup_name_from_8_3(ctx,
					    		start,
							&unmangled,
							conn->params)) {
					char *tmp;
					size_t start_ofs =
					    start - smb_fname->base_name;

					if (*dirpath != '\0') {
						tmp = talloc_asprintf(
							smb_fname, "%s/%s",
							dirpath, unmangled);
						TALLOC_FREE(unmangled);
					}
					else {
						tmp = unmangled;
					}
					if (tmp == NULL) {
						DEBUG(0, ("talloc failed\n"));
						status = NT_STATUS_NO_MEMORY;
						goto err;
					}
					TALLOC_FREE(smb_fname->base_name);
					smb_fname->base_name = tmp;
					start =
					    smb_fname->base_name + start_ofs;
					end = start + strlen(start);
				}

				DEBUG(5,("New file %s\n",start));
				goto done;
			}


			/*
			 * Restore the rest of the string. If the string was
			 * mangled the size may have changed.
			 */
			if (end) {
				char *tmp;
				size_t start_ofs =
				    start - smb_fname->base_name;

				if (*dirpath != '\0') {
					tmp = talloc_asprintf(smb_fname,
						"%s/%s/%s", dirpath,
						found_name, end+1);
				}
				else {
					tmp = talloc_asprintf(smb_fname,
						"%s/%s", found_name,
						end+1);
				}
				if (tmp == NULL) {
					DEBUG(0, ("talloc_asprintf failed\n"));
					status = NT_STATUS_NO_MEMORY;
					goto err;
				}
				TALLOC_FREE(smb_fname->base_name);
				smb_fname->base_name = tmp;
				start = smb_fname->base_name + start_ofs;
				end = start + strlen(found_name);
				*end = '\0';
			} else {
				char *tmp;
				size_t start_ofs =
				    start - smb_fname->base_name;

				if (*dirpath != '\0') {
					tmp = talloc_asprintf(smb_fname,
						"%s/%s", dirpath,
						found_name);
				} else {
					tmp = talloc_strdup(smb_fname,
						found_name);
				}
				if (tmp == NULL) {
					DEBUG(0, ("talloc failed\n"));
					status = NT_STATUS_NO_MEMORY;
					goto err;
				}
				TALLOC_FREE(smb_fname->base_name);
				smb_fname->base_name = tmp;
				start = smb_fname->base_name + start_ofs;

				/*
				 * We just scanned for, and found the end of
				 * the path. We must return a valid stat struct
				 * if it exists. JRA.
				 */

				if (posix_pathnames) {
					ret = SMB_VFS_LSTAT(conn, smb_fname);
				} else {
					ret = SMB_VFS_STAT(conn, smb_fname);
				}

				if (ret != 0) {
					SET_STAT_INVALID(smb_fname->st);
				}
			}

			TALLOC_FREE(found_name);
		} /* end else */

#ifdef DEVELOPER
		/*
		 * This sucks!
		 * We should never provide different behaviors
		 * depending on DEVELOPER!!!
		 */
		if (VALID_STAT(smb_fname->st)) {
			bool delete_pending;
			uint32_t name_hash;

			status = file_name_hash(conn,
					smb_fname_str_dbg(smb_fname),
					&name_hash);
			if (!NT_STATUS_IS_OK(status)) {
				goto fail;
			}

			get_file_infos(vfs_file_id_from_sbuf(conn,
							     &smb_fname->st),
				       name_hash,
				       &delete_pending, NULL);
			if (delete_pending) {
				status = NT_STATUS_DELETE_PENDING;
				goto fail;
			}
		}
#endif

		/*
		 * Add to the dirpath that we have resolved so far.
		 */

		if (*dirpath != '\0') {
			char *tmp = talloc_asprintf(ctx,
					"%s/%s", dirpath, start);
			if (!tmp) {
				DEBUG(0, ("talloc_asprintf failed\n"));
				status = NT_STATUS_NO_MEMORY;
				goto err;
			}
			TALLOC_FREE(dirpath);
			dirpath = tmp;
		}
		else {
			TALLOC_FREE(dirpath);
			if (!(dirpath = talloc_strdup(ctx,start))) {
				DEBUG(0, ("talloc_strdup failed\n"));
				status = NT_STATUS_NO_MEMORY;
				goto err;
			}
		}

		/*
		 * Cache the dirpath thus far. Don't cache a name with mangled
		 * or wildcard components as this can change the size.
		 */
		if(!component_was_mangled && !name_has_wildcard) {
			stat_cache_add(orig_path, dirpath,
					conn->case_sensitive);
		}

		/*
		 * Restore the / that we wiped out earlier.
		 */
		if (end) {
			*end = '/';
		}
	}

	/*
	 * Cache the full path. Don't cache a name with mangled or wildcard
	 * components as this can change the size.
	 */

	if(!component_was_mangled && !name_has_wildcard) {
		stat_cache_add(orig_path, smb_fname->base_name,
			       conn->case_sensitive);
	}

	/*
	 * The name has been resolved.
	 */

	DEBUG(5,("conversion finished %s -> %s\n", orig_path,
		 smb_fname->base_name));

 done:
	/* Add back the stream if one was stripped off originally. */
	if (stream != NULL) {
		smb_fname->stream_name = stream;

		/* Check path now that the base_name has been converted. */
		status = build_stream_path(ctx, conn, orig_path, smb_fname);
		if (!NT_STATUS_IS_OK(status)) {
			goto fail;
		}
	}
	TALLOC_FREE(dirpath);
	*smb_fname_out = smb_fname;
	return NT_STATUS_OK;
 fail:
	DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start));
	if (*dirpath != '\0') {
		smb_fname->base_name = talloc_asprintf(smb_fname, "%s/%s",
						       dirpath, start);
	} else {
		smb_fname->base_name = talloc_strdup(smb_fname, start);
	}
	if (!smb_fname->base_name) {
		DEBUG(0, ("talloc_asprintf failed\n"));
		status = NT_STATUS_NO_MEMORY;
		goto err;
	}

	*smb_fname_out = smb_fname;
	TALLOC_FREE(dirpath);
	return status;
 err:
	TALLOC_FREE(smb_fname);
	return status;
}