#include "lib/global_contexts.h"
#include "source3/lib/substitute.h"
-/**********************************************************************
- Function to determine if a given sharename matches a connection.
-**********************************************************************/
-
-static bool msdfs_servicename_matches_connection(struct connection_struct *conn,
- const char *servicename,
- const char *vfs_user)
-{
- const struct loadparm_substitution *lp_sub =
- loadparm_s3_global_substitution();
- char *conn_servicename = NULL;
- int snum;
- bool match = false;
-
- snum = SNUM(conn);
-
- conn_servicename = lp_servicename(talloc_tos(), lp_sub, snum);
- if (conn_servicename == NULL) {
- DBG_ERR("lp_servicename() failed, OOM!\n");
- return false;
- }
-
- if (strequal(servicename, conn_servicename)) {
- match = true;
- goto done;
- }
- if (strequal(servicename, HOMES_NAME)) {
- match = true;
- goto done;
- }
- if (strequal(vfs_user, conn_servicename)) {
- match = true;
- goto done;
- }
-done:
- TALLOC_FREE(conn_servicename);
- return match;
-}
-
/**********************************************************************
Parse a DFS pathname of the form(s)
return status;
}
-/**********************************************************************
- Parse a DFS pathname of the form /hostname/service/reqpath
- into the dfs_path structure.
-
- NB. srvstr_get_path_internal() now *always* calls
- check_path_syntax_XXX() on an incoming name, so
- the path separator is now always '/', even from
- Windows clients.
-
- Unfortunately, due to broken clients who might set the
- SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
- send a local path, we have to cope with that too....
-
- If conn != NULL then ensure the provided service is
- the one pointed to by the connection.
-
- This version does everything using pointers within one copy of the
- pathname string, talloced on the struct dfs_path pointer (which
- must be talloced). This may be too clever to live....
- JRA.
-**********************************************************************/
-
-static NTSTATUS parse_dfs_path(TALLOC_CTX *ctx,
- connection_struct *conn,
- const char *pathname,
- char **_hostname,
- char **_servicename,
- char **_remaining_path)
-{
- char *hostname = NULL;
- char *pathname_local = NULL;
- char *p = NULL;
- char *servicename = NULL;
- char *reqpath = NULL;
- char *eos_ptr = NULL;
- bool servicename_matches = false;
- bool using_smb1 = !conn->sconn->using_smb2;
-
- pathname_local = talloc_strdup(ctx, pathname);
- if (pathname_local == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- /*
- * parse_dfs_path() is only called from
- * dfs_filename_convert() with SMB1/2/3 DFS
- * names. Ensure we only have to cope with
- * '/' separators.
- */
- string_replace(pathname_local, '\\', '/');
-
- /* Get a pointer to the terminating '\0' */
- eos_ptr = &pathname_local[strlen(pathname_local)];
- p = pathname_local;
-
- /*
- * SMB1 DFS paths sent to the fileserver should start with
- * the path separator '/'. However, libsmbclient libraries
- * will set the DFS bit on SMB1 calls and then send non-DFS
- * paths. We must cope with this.
- *
- * Note SMB2 paths sent to the fileserver never start with
- * the path separator '/'.
- */
-
- if (using_smb1 && (*p != '/')) {
- DBG_ERR("path %s doesn't start with /\n", p);
- /*
- * Possibly client sent a local path by mistake.
- * Try and convert to a local path.
- * Note that this is an SMB1-only fallback
- * to cope with known broken SMB1 clients.
- */
-
- hostname = eos_ptr; /* "" */
- servicename = eos_ptr; /* "" */
-
- DBG_ERR("trying to convert %s to a local path\n", p);
- goto local_path;
- }
-
- /*
- * Safe to use on talloc'ed string as it only shrinks.
- * It also doesn't affect the eos_ptr.
- */
- trim_char(p, '/', '/');
-
- DBG_DEBUG("p = |%s| after trimming /'s\n", p);
-
- /* Now tokenize. */
- /* Parse out hostname. */
- p = strchr(p,'/');
- if(p == NULL) {
- DBG_ERR("can't parse hostname from path %s\n", pathname_local);
- /*
- * Possibly client sent a local path by mistake.
- * Try and convert to a local path.
- */
-
- hostname = eos_ptr; /* "" */
- servicename = eos_ptr; /* "" */
-
- p = pathname_local;
- DBG_ERR("trying to convert %s to a local path\n", p);
- goto local_path;
- }
- *p = '\0';
- hostname = pathname_local;
-
- DBG_DEBUG("hostname: %s\n", hostname);
-
- /* Parse out servicename. */
- servicename = p+1;
- p = strchr(servicename, '/');
- if (p) {
- *p = '\0';
- }
-
- /* Is this really our servicename ? */
- servicename_matches = msdfs_servicename_matches_connection(
- conn,
- servicename,
- get_current_username());
-
- if (!servicename_matches) {
- DBG_ERR("%s is not our servicename\n", servicename);
-
- /*
- * Possibly client sent a local path by mistake.
- * Try and convert to a local path.
- */
-
- /* Repair the path - replace the sepchar's
- we nulled out */
- servicename--;
- *servicename = '/';
- if (p) {
- *p = '/';
- }
-
- hostname = eos_ptr; /* "" */
- servicename = eos_ptr; /* "" */
-
- p = pathname_local;
- DBG_ERR("trying to convert %s to a local path\n",
- pathname_local);
- goto local_path;
- }
-
- DBG_DEBUG("servicename: %s\n", servicename);
-
- if(p == NULL) {
- /* Client sent self referral \server\share. */
- reqpath = eos_ptr; /* "" */
- goto out;
- }
-
- p++;
-
- local_path:
-
- /*
- * As check_path_syntax_XXX() has already been
- * called we know this is a normal path containing
- * '/' separators.
- */
-
- reqpath = p;
-
- out:
-
- DBG_DEBUG("rest of the path: %s\n", reqpath);
-
- if (_hostname != NULL) {
- *_hostname = talloc_strdup(ctx, hostname);
- if (*_hostname == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- }
- if (_servicename != NULL) {
- *_servicename = talloc_strdup(ctx, servicename);
- if (*_servicename == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- }
- if (_remaining_path != NULL) {
- *_remaining_path = talloc_strdup(ctx, reqpath);
- if (*_remaining_path == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- }
- TALLOC_FREE(pathname_local);
- return NT_STATUS_OK;
-}
-
/********************************************************
Fake up a connection struct for the VFS layer, for use in
applications (such as the python bindings), that do not want the
return status;
}
-/*****************************************************************
- Decides if a dfs pathname should be redirected or not.
- If not, the pathname is converted to a tcon-relative local unix path
- This is now a simple wrapper around parse_dfs_path()
- as it does all the required checks.
-*****************************************************************/
-
-NTSTATUS dfs_filename_convert(TALLOC_CTX *ctx,
- connection_struct *conn,
- uint32_t ucf_flags,
- const char *dfs_path_in,
- char **pp_path_out)
-{
- char *reqpath = NULL;
- NTSTATUS status;
-
- /*
- * We must use the non-strict version of parse_dfs_path for
- * pathnames sent to the fileserver over SMB1/2/3.
- * libsmbclient callers always set the FLAGS2_DFS_PATHNAMES
- * but then don't send a DFS path in (for example) FindFirst
- * or other calls. This is a problem with our client libraries
- * for both SMB1 and SMB2+ and will remain so whilst broken
- * versions of libsmbclient are being used.
- */
-
- status = parse_dfs_path(ctx,
- conn,
- dfs_path_in,
- NULL, /* hostname */
- NULL, /* servicename */
- &reqpath);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- /*
- * If parse_dfs_path fell back to a local path
- * after skipping hostname or servicename, ensure
- * we still have called check_path_syntax()
- * on the full returned local path. check_path_syntax()
- * is idempotent so this is safe.
- */
- if (ucf_flags & UCF_POSIX_PATHNAMES) {
- status = check_path_syntax_posix(reqpath);
- } else {
- status = check_path_syntax(reqpath);
- }
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- /*
- * Previous (and current logic) just ignores
- * the server, share components if a DFS
- * path is sent on a non-DFS share except to
- * check that they match an existing share. Should
- * we tighten this up to return an error here ?
- */
- *pp_path_out = reqpath;
- return NT_STATUS_OK;
-}
-
/**********************************************************************
Return a self referral.
**********************************************************************/