summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/msdfs.h7
-rw-r--r--source3/lib/util.c3
-rw-r--r--source3/libsmb/clidfs.c288
-rw-r--r--source3/rpc_server/srv_dfs_nt.c12
-rw-r--r--source3/smbd/dir.c6
-rw-r--r--source3/smbd/msdfs.c829
-rw-r--r--source3/smbd/nttrans.c33
-rw-r--r--source3/smbd/reply.c180
-rw-r--r--source3/smbd/trans2.c43
9 files changed, 813 insertions, 588 deletions
diff --git a/source3/include/msdfs.h b/source3/include/msdfs.h
index bf553f4a99..05cfe4e102 100644
--- a/source3/include/msdfs.h
+++ b/source3/include/msdfs.h
@@ -51,7 +51,7 @@ struct referral {
};
struct junction_map {
- pstring service_name;
+ fstring service_name;
pstring volume_name;
pstring comment;
int referral_count;
@@ -59,9 +59,10 @@ struct junction_map {
};
struct dfs_path {
- pstring hostname;
- pstring servicename;
+ fstring hostname;
+ fstring servicename;
pstring reqpath;
+ BOOL posix_path;
};
#define init_dfsroot(conn, inbuf, outbuf) \
diff --git a/source3/lib/util.c b/source3/lib/util.c
index aa8aaa0628..6789a12a1e 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -2091,6 +2091,9 @@ BOOL is_myname_or_ipaddr(const char *s)
/* check for loopback */
+ if (strequal(servername, "127.0.0.1"))
+ return True;
+
if (strequal(servername, "localhost"))
return True;
diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c
index e2cfd12114..4009b98b41 100644
--- a/source3/libsmb/clidfs.c
+++ b/source3/libsmb/clidfs.c
@@ -25,7 +25,7 @@
/********************************************************************
Important point.
- DFS paths are of the form \server\share\<pathname> (the \ characters
+ DFS paths are *always* of the form \server\share\<pathname> (the \ characters
are not C escaped here).
- but if we're using POSIX paths then <pathname> may contain
@@ -205,14 +205,14 @@ static void cli_cm_set_mntpoint( struct cli_state *c, const char *mnt )
if ( p ) {
pstrcpy( p->mount, mnt );
- clean_name( p->mount );
+ clean_name(p->mount);
}
}
/****************************************************************************
****************************************************************************/
-const char * cli_cm_get_mntpoint( struct cli_state *c )
+const char *cli_cm_get_mntpoint( struct cli_state *c )
{
struct client_connection *p;
int i;
@@ -232,8 +232,9 @@ const char * cli_cm_get_mntpoint( struct cli_state *c )
Add a new connection to the list
********************************************************************/
-static struct cli_state* cli_cm_connect( const char *server, const char *share,
- BOOL show_hdr )
+static struct cli_state *cli_cm_connect( const char *server,
+ const char *share,
+ BOOL show_hdr)
{
struct client_connection *node;
@@ -258,7 +259,7 @@ static struct cli_state* cli_cm_connect( const char *server, const char *share,
Return a connection to a server.
********************************************************************/
-static struct cli_state* cli_cm_find( const char *server, const char *share )
+static struct cli_state *cli_cm_find( const char *server, const char *share )
{
struct client_connection *p;
@@ -275,7 +276,9 @@ static struct cli_state* cli_cm_find( const char *server, const char *share )
global variable as a side-effect (but only if the connection is successful).
****************************************************************************/
-struct cli_state* cli_cm_open( const char *server, const char *share, BOOL show_hdr )
+struct cli_state *cli_cm_open(const char *server,
+ const char *share,
+ BOOL show_hdr)
{
struct cli_state *c;
@@ -283,8 +286,9 @@ struct cli_state* cli_cm_open( const char *server, const char *share, BOOL show_
c = cli_cm_find( server, share );
- if ( !c )
- c = cli_cm_connect( server, share, show_hdr );
+ if ( !c ) {
+ c = cli_cm_connect(server, share, show_hdr);
+ }
return c;
}
@@ -306,7 +310,6 @@ void cli_cm_shutdown( void )
}
connections = NULL;
-
return;
}
@@ -369,20 +372,21 @@ void cli_cm_set_dest_ip(struct in_addr ip )
split a dfs path into the server, share name, and extrapath components
**********************************************************************/
-static void split_dfs_path( const char *nodepath, fstring server, fstring share, fstring extrapath )
+static void split_dfs_path( const char *nodepath, fstring server, fstring share, pstring extrapath )
{
char *p, *q;
pstring path;
pstrcpy( path, nodepath );
- if ( path[0] != '\\' )
+ if ( path[0] != '\\' ) {
return;
+ }
p = strchr_m( path + 1, '\\' );
-
- if ( !p )
+ if ( !p ) {
return;
+ }
*p = '\0';
p++;
@@ -392,9 +396,9 @@ static void split_dfs_path( const char *nodepath, fstring server, fstring share,
if (q != NULL) {
*q = '\0';
q++;
- fstrcpy( extrapath, q );
+ pstrcpy( extrapath, q );
} else {
- fstrcpy( extrapath, '\0' );
+ pstrcpy( extrapath, '\0' );
}
fstrcpy( share, p );
@@ -402,83 +406,66 @@ static void split_dfs_path( const char *nodepath, fstring server, fstring share,
}
/****************************************************************************
- return the original path truncated at the first wildcard character
- (also strips trailing \'s). Trust the caller to provide a NULL
+ Return the original path truncated at the directory component before
+ the first wildcard character. Trust the caller to provide a NULL
terminated string
****************************************************************************/
-static void clean_path( pstring clean, const char *path )
+static void clean_path(const char *path, pstring path_out)
{
- int len;
- char *p;
- pstring newpath;
+ size_t len;
+ char *p1, *p2, *p;
- pstrcpy( newpath, path );
- p = newpath;
-
- while ( p ) {
- /* first check for '*' */
-
- p = strrchr_m( newpath, '*' );
- if ( p ) {
- *p = '\0';
- p = newpath;
- continue;
+ /* No absolute paths. */
+ while (IS_DIRECTORY_SEP(*path)) {
+ path++;
+ }
+
+ pstrcpy(path_out, path);
+
+ p1 = strchr_m(path_out, '*');
+ p2 = strchr_m(path_out, '?');
+
+ if (p1 || p2) {
+ if (p1 && p2) {
+ p = MIN(p1,p2);
+ } else if (!p1) {
+ p = p2;
+ } else {
+ p = p1;
}
-
- /* first check for '?' */
-
- p = strrchr_m( newpath, '?' );
- if ( p ) {
+ *p = '\0';
+
+ /* Now go back to the start of this component. */
+ p1 = strrchr_m(path_out, '/');
+ p2 = strrchr_m(path_out, '\\');
+ p = MAX(p1,p2);
+ if (p) {
*p = '\0';
- p = newpath;
}
}
-
- /* strip a trailing backslash */
-
- len = strlen( newpath );
- if ( (len > 0) && (newpath[len-1] == '\\' || newpath[len-1] == '/') )
- newpath[len-1] = '\0';
-
- pstrcpy( clean, newpath );
+
+ /* Strip any trailing separator */
+
+ len = strlen(path_out);
+ if ( (len > 0) && IS_DIRECTORY_SEP(path_out[len-1])) {
+ path_out[len-1] = '\0';
+ }
}
/****************************************************************************
****************************************************************************/
-BOOL cli_dfs_make_full_path( pstring path, const char *server, const char *share,
- const char *dir )
+static void cli_dfs_make_full_path( struct cli_state *cli,
+ const char *dir,
+ pstring path_out)
{
- pstring servicename;
- char *sharename;
- const char *directory;
-
-
- /* make a copy so we don't modify the global string 'service' */
-
- pstrcpy(servicename, share);
- sharename = servicename;
-
- if (*sharename == '\\') {
-
- server = sharename+2;
- sharename = strchr_m(server,'\\');
-
- if (!sharename)
- return False;
-
- *sharename = 0;
- sharename++;
+ /* Ensure the extrapath doesn't start with a separator. */
+ while (IS_DIRECTORY_SEP(*dir)) {
+ dir++;
}
- directory = dir;
- if ( *directory == '\\' || *directory == '/' )
- directory++;
-
- pstr_sprintf( path, "\\%s\\%s\\%s", server, sharename, directory );
-
- return True;
+ pstr_sprintf( path_out, "\\%s\\%s\\%s", cli->desthost, cli->share, dir);
}
/********************************************************************
@@ -504,9 +491,11 @@ static BOOL cli_dfs_check_error( struct cli_state *cli, NTSTATUS status )
get the dfs referral link
********************************************************************/
-BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
- CLIENT_DFS_REFERRAL**refs, size_t *num_refs,
- uint16 *consumed)
+BOOL cli_dfs_get_referral( struct cli_state *cli,
+ const char *path,
+ CLIENT_DFS_REFERRAL**refs,
+ size_t *num_refs,
+ uint16 *consumed)
{
unsigned int data_len = 0;
unsigned int param_len = 0;
@@ -550,10 +539,9 @@ BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
uint16 ref_size;
int i;
uint16 node_offset;
-
-
+
referrals = SMB_XMALLOC_ARRAY( CLIENT_DFS_REFERRAL, num_referrals );
-
+
/* start at the referrals array */
p = rdata+8;
@@ -575,7 +563,6 @@ BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
p += ref_size;
}
-
}
*num_refs = num_referrals;
@@ -587,17 +574,21 @@ BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
return True;
}
+
/********************************************************************
********************************************************************/
-BOOL cli_resolve_path( const char *mountpt, struct cli_state *rootcli, const char *path,
- struct cli_state **targetcli, pstring targetpath )
+BOOL cli_resolve_path( const char *mountpt,
+ struct cli_state *rootcli,
+ const char *path,
+ struct cli_state **targetcli,
+ pstring targetpath)
{
CLIENT_DFS_REFERRAL *refs = NULL;
size_t num_refs;
uint16 consumed;
struct cli_state *cli_ipc;
- pstring fullpath, cleanpath, extrapath;
+ pstring dfs_path, cleanpath, extrapath;
int pathlen;
fstring server, share;
struct cli_state *newcli;
@@ -612,22 +603,29 @@ BOOL cli_resolve_path( const char *mountpt, struct cli_state *rootcli, const cha
return False;
}
- *targetcli = NULL;
-
- /* send a trans2_query_path_info to check for a referral */
-
- clean_path( cleanpath, path );
- cli_dfs_make_full_path( fullpath, rootcli->desthost, rootcli->share, cleanpath );
+ /* Don't do anything if this is not a DFS root. */
- /* don't bother continuing if this is not a dfs root */
-
- if ( !rootcli->dfsroot || cli_qpathinfo_basic( rootcli, fullpath, &sbuf, &attributes ) ) {
+ if ( !rootcli->dfsroot) {
*targetcli = rootcli;
pstrcpy( targetpath, path );
return True;
}
- /* special case where client asked for a path that does not exist */
+ *targetcli = NULL;
+
+ /* Send a trans2_query_path_info to check for a referral. */
+
+ clean_path(path, cleanpath);
+ cli_dfs_make_full_path(rootcli, cleanpath, dfs_path );
+
+ if (cli_qpathinfo_basic( rootcli, dfs_path, &sbuf, &attributes ) ) {
+ /* This is an ordinary path, just return it. */
+ *targetcli = rootcli;
+ pstrcpy( targetpath, path );
+ goto done;
+ }
+
+ /* Special case where client asked for a path that does not exist */
if ( cli_dfs_check_error(rootcli, NT_STATUS_OBJECT_NAME_NOT_FOUND) ) {
*targetcli = rootcli;
@@ -635,87 +633,97 @@ BOOL cli_resolve_path( const char *mountpt, struct cli_state *rootcli, const cha
goto done;
}
- /* we got an error, check for DFS referral */
-
+ /* We got an error, check for DFS referral. */
+
if ( !cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED)) {
return False;
}
- /* check for the referral */
+ /* Check for the referral. */
if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) ) {
return False;
}
- if ( !cli_dfs_get_referral(cli_ipc, fullpath, &refs, &num_refs, &consumed)
+ if ( !cli_dfs_get_referral(cli_ipc, dfs_path, &refs, &num_refs, &consumed)
|| !num_refs ) {
return False;
}
- /* just store the first referral for now
- Make sure to recreate the original string including any wildcards */
-
- cli_dfs_make_full_path( fullpath, rootcli->desthost, rootcli->share, path );
- pathlen = strlen( fullpath )*2;
- consumed = MIN(pathlen, consumed );
- pstrcpy( targetpath, &fullpath[consumed/2] );
+ /* Just store the first referral for now. */
split_dfs_path( refs[0].dfspath, server, share, extrapath );
- SAFE_FREE( refs );
+ SAFE_FREE(refs);
- if (strlen(extrapath) > 0) {
- string_append(&temppath, extrapath);
- string_append(&temppath, targetpath);
- pstrcpy( targetpath, temppath );
- }
+ /* Make sure to recreate the original string including any wildcards. */
- /* open the connection to the target path */
+ cli_dfs_make_full_path( rootcli, path, dfs_path);
+ pathlen = strlen( dfs_path )*2;
+ consumed = MIN(pathlen, consumed );
+ pstrcpy( targetpath, &dfs_path[consumed/2] );
+ dfs_path[consumed/2] = '\0';
+
+ /*
+ * targetpath is now the unconsumed part of the path.
+ * dfs_path is now the consumed part of the path (in \server\share\path format).
+ */
+
+ /* Open the connection to the target server & share */
if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) {
- d_printf("Unable to follow dfs referral [//%s/%s]\n",
+ d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
server, share );
-
return False;
}
+ if (strlen(extrapath) > 0) {
+ string_append(&temppath, extrapath);
+ string_append(&temppath, targetpath);
+ pstrcpy( targetpath, temppath );
+ }
+
/* parse out the consumed mount path */
/* trim off the \server\share\ */
- fullpath[consumed/2] = '\0';
- clean_name( fullpath );
- if ((ppath = strchr_m( fullpath, '\\' )) == NULL) {
+ ppath = dfs_path;
+
+ if (*ppath != '\\') {
+ d_printf("cli_resolve_path: dfs_path (%s) not in correct format.\n",
+ dfs_path );
return False;
}
- if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) {
+
+ ppath++; /* Now pointing at start of server name. */
+
+ if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) {
return False;
}
- {
- char *p1, *p2;
-
- /* Last component can be '\\' or '/' posix path. */
- p1 = strchr_m( ppath+1, '\\' );
- p2 = strchr_m( ppath+1, '/' );
+ ppath++; /* Now pointing at start of share name. */
- ppath = MAX(p1,p2);
-
- if (ppath == NULL) {
- return False;
- }
+ if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) {
+ return False;
}
- ppath++;
-
+ ppath++; /* Now pointing at path component. */
+
pstr_sprintf( newmount, "%s\\%s", mountpt, ppath );
+
cli_cm_set_mntpoint( *targetcli, newmount );
- /* check for another dfs referral, note that we are not
- checking for loops here */
+ /* Check for another dfs referral, note that we are not
+ checking for loops here. */
if ( !strequal( targetpath, "\\" ) && !strequal( targetpath, "/")) {
if ( cli_resolve_path( newmount, *targetcli, targetpath, &newcli, newpath ) ) {
+ /*
+ * When cli_resolve_path returns true here it's always
+ * returning the complete path in newpath, so we're done
+ * here.
+ */
*targetcli = newcli;
pstrcpy( targetpath, newpath );
+ return True;
}
}
@@ -723,9 +731,8 @@ BOOL cli_resolve_path( const char *mountpt, struct cli_state *rootcli, const cha
/* If returning True ensure we return a dfs root full path. */
if ( (*targetcli)->dfsroot ) {
- pstrcpy( fullpath, targetpath );
- cli_dfs_make_full_path( targetpath, (*targetcli)->desthost,
- (*targetcli)->share, fullpath);
+ pstrcpy(dfs_path, targetpath );
+ cli_dfs_make_full_path( *targetcli, dfs_path, targetpath);
}
return True;
@@ -743,7 +750,7 @@ BOOL cli_check_msdfs_proxy( struct cli_state *cli, const char *sharename,
pstring fullpath;
BOOL res;
uint16 cnum;
- fstring newextrapath;
+ pstring newextrapath;
if ( !cli || !sharename )
return False;
@@ -752,8 +759,9 @@ BOOL cli_check_msdfs_proxy( struct cli_state *cli, const char *sharename,
/* special case. never check for a referral on the IPC$ share */
- if ( strequal( sharename, "IPC$" ) )
+ if ( strequal( sharename, "IPC$" ) ) {
return False;
+ }
/* send a trans2_query_path_info to check for a referral */
diff --git a/source3/rpc_server/srv_dfs_nt.c b/source3/rpc_server/srv_dfs_nt.c
index 98818826df..c7adffd62f 100644
--- a/source3/rpc_server/srv_dfs_nt.c
+++ b/source3/rpc_server/srv_dfs_nt.c
@@ -42,6 +42,8 @@ WERROR _dfs_Add(pipes_struct *p, struct dfs_Add *r)
{
struct junction_map jn;
struct referral* old_referral_list = NULL;
+ BOOL self_ref = False;
+ int consumedcnt = 0;
BOOL exists = False;
pstring altpath;
@@ -59,7 +61,7 @@ WERROR _dfs_Add(pipes_struct *p, struct dfs_Add *r)
pstrcat(altpath, r->in.share);
/* The following call can change the cwd. */
- if(get_referred_path(p->mem_ctx, r->in.path, &jn, NULL, NULL)) {
+ if(get_referred_path(p->mem_ctx, r->in.path, &jn, &consumedcnt, &self_ref)) {
exists = True;
jn.referral_count += 1;
old_referral_list = jn.referral_list;
@@ -96,6 +98,8 @@ WERROR _dfs_Add(pipes_struct *p, struct dfs_Add *r)
WERROR _dfs_Remove(pipes_struct *p, struct dfs_Remove *r)
{
struct junction_map jn;
+ BOOL self_ref = False;
+ int consumedcnt = 0;
BOOL found = False;
pstring altpath;
@@ -115,7 +119,7 @@ WERROR _dfs_Remove(pipes_struct *p, struct dfs_Remove *r)
DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n",
r->in.path, r->in.server, r->in.share));
- if(!get_referred_path(p->mem_ctx, r->in.path, &jn, NULL, NULL)) {
+ if(!get_referred_path(p->mem_ctx, r->in.path, &jn, &consumedcnt, &self_ref)) {
return WERR_DFS_NO_SUCH_VOL;
}
@@ -302,13 +306,14 @@ WERROR _dfs_GetInfo(pipes_struct *p, struct dfs_GetInfo *r)
{
int consumedcnt = sizeof(pstring);
struct junction_map jn;
+ BOOL self_ref = False;
BOOL ret;
if(!create_junction(r->in.path, &jn))
return WERR_DFS_NO_SUCH_SERVER;
/* The following call can change the cwd. */
- if(!get_referred_path(p->mem_ctx, r->in.path, &jn, &consumedcnt, NULL) || consumedcnt < strlen(r->in.path)) {
+ if(!get_referred_path(p->mem_ctx, r->in.path, &jn, &consumedcnt, &self_ref) || consumedcnt < strlen(r->in.path)) {
vfs_ChDir(p->conn,p->conn->connectpath);
return WERR_DFS_NO_SUCH_VOL;
}
@@ -456,4 +461,3 @@ WERROR _dfs_SetInfo2(pipes_struct *p, struct dfs_SetInfo2 *r)
p->rng_fault_state = True;
return WERR_NOT_SUPPORTED;
}
-
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
index 2795b2a24b..db3e155ae4 100644
--- a/source3/smbd/dir.c
+++ b/source3/smbd/dir.c
@@ -1017,6 +1017,7 @@ BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *
}
if (hide_unreadable || hide_unwriteable || hide_special) {
+ pstring link_target;
char *entry = NULL;
if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
@@ -1026,10 +1027,7 @@ BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *
/* If it's a dfs symlink, ignore _hide xxxx_ options */
if (lp_host_msdfs() &&
lp_msdfs_root(SNUM(conn)) &&
- /* We get away with NULL talloc ctx here as
- we're not interested in the link contents
- so we have nothing to free. */
- is_msdfs_link(NULL, conn, entry, NULL, NULL, NULL)) {
+ is_msdfs_link(conn, entry, link_target, NULL)) {
SAFE_FREE(entry);
return True;
}
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index 861588e6b7..ae2009ad38 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -1,7 +1,7 @@
/*
Unix SMB/Netbios implementation.
Version 3.0
- MSDfs services for Samba
+ MSDFS services for Samba
Copyright (C) Shirish Kalele 2000
Copyright (C) Jeremy Allison 2007
@@ -27,105 +27,142 @@
extern uint32 global_client_caps;
/**********************************************************************
- Parse the pathname of the form \hostname\service\reqpath
- into the dfs_path structure
- **********************************************************************/
+ Parse a DFS pathname of the form \hostname\service\reqpath
+ into the dfs_path structure.
+ If POSIX pathnames is true, the pathname may also be of the
+ form /hostname/service/reqpath.
+ We cope with either here.
+
+ 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....
+
+ JRA.
+**********************************************************************/
-static BOOL parse_dfs_path(const char *pathname, struct dfs_path *pdp)
+static NTSTATUS parse_dfs_path(const char *pathname,
+ BOOL allow_wcards,
+ struct dfs_path *pdp,
+ BOOL *ppath_contains_wcard)
{
pstring pathname_local;
- char *p, *temp;
+ char *p,*temp;
+ NTSTATUS status = NT_STATUS_OK;
+ char sepchar;
+
+ ZERO_STRUCTP(pdp);
pstrcpy(pathname_local,pathname);
p = temp = pathname_local;
- ZERO_STRUCTP(pdp);
+ pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
- trim_char(temp,'\\','\\');
- DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp));
+ sepchar = pdp->posix_path ? '/' : '\\';
- /* now tokenize */
- /* parse out hostname */
- p = strchr_m(temp,'\\');
- if(p == NULL) {
- return False;
- }
- *p = '\0';
- pstrcpy(pdp->hostname,temp);
- DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
+ if (*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.
+ */
- /* parse out servicename */
- temp = p+1;
- p = strchr_m(temp,'\\');
- if(p == NULL) {
- pstrcpy(pdp->servicename,temp);
- pdp->reqpath[0] = '\0';
- return True;
+ pdp->hostname[0] = '\0';
+ pdp->servicename[0] = '\0';
+
+ /* 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;
}
- *p = '\0';
- pstrcpy(pdp->servicename,temp);
- DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
- /* rest is reqpath */
- check_path_syntax(pdp->reqpath, p+1);
+ trim_char(temp,sepchar,sepchar);
- DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
- return True;
-}
+ DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
+ temp, sepchar));
-/**********************************************************************
- Parse the pathname of the form /hostname/service/reqpath
- into the dfs_path structure
- This code is dependent on the fact that check_path_syntax() will
- convert '\\' characters to '/'.
- **********************************************************************/
+ /* 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.
+ */
-static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path *pdp, BOOL allow_wcards)
-{
- pstring pathname_local;
- char *p,*temp;
- const char sepchar = '/';
+ pdp->hostname[0] = '\0';
+ pdp->servicename[0] = '\0';
- pstrcpy(pathname_local,pathname);
- p = temp = pathname_local;
+ p = temp;
+ DEBUG(10,("parse_dfs_path: trying to convert %s to a local path\n",
+ temp));
+ goto local_path;
+ }
+ *p = '\0';
+ fstrcpy(pdp->hostname,temp);
+ DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
- ZERO_STRUCTP(pdp);
+ /* If we got a hostname, is it ours (or an IP address) ? */
+ if (!is_myname_or_ipaddr(pdp->hostname)) {
+ /* Repair path. */
+ *p = sepchar;
+ DEBUG(10,("parse_dfs_path: hostname %s isn't ours. Try local path from path %s\n",
+ pdp->hostname, temp));
+ /*
+ * Possibly client sent a local path by mistake.
+ * Try and convert to a local path.
+ */
- trim_char(temp,sepchar,sepchar);
- DEBUG(10,("temp in parse_processed_dfs_path: .%s. after trimming /'s\n",temp));
+ pdp->hostname[0] = '\0';
+ pdp->servicename[0] = '\0';
- /* now tokenize */
- /* parse out hostname */
- p = strchr_m(temp,sepchar);
- if(p == NULL) {
- return False;
+ p = temp;
+ DEBUG(10,("parse_dfs_path: trying to convert %s to a local path\n",
+ temp));
+ goto local_path;
}
- *p = '\0';
- pstrcpy(pdp->hostname,temp);
- DEBUG(10,("parse_processed_dfs_path: hostname: %s\n",pdp->hostname));
- /* parse out servicename */
+ /* Parse out servicename. */
temp = p+1;
p = strchr_m(temp,sepchar);
if(p == NULL) {
- pstrcpy(pdp->servicename,temp);
+ fstrcpy(pdp->servicename,temp);
pdp->reqpath[0] = '\0';
- return True;
+ return NT_STATUS_OK;
}
*p = '\0';
- pstrcpy(pdp->servicename,temp);
- DEBUG(10,("parse_processed_dfs_path: servicename: %s\n",pdp->servicename));
+ fstrcpy(pdp->servicename,temp);
+ DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
+
+ p++;
+
+ local_path:
- /* rest is reqpath */
- if (allow_wcards) {
- BOOL path_contains_wcard;
- check_path_syntax_wcard(pdp->reqpath, p+1, &path_contains_wcard);
+ *ppath_contains_wcard = False;
+
+ /* Rest is reqpath. */
+ if (pdp->posix_path) {
+ status = check_path_syntax_posix(pdp->reqpath, p);
} else {
- check_path_syntax(pdp->reqpath, p+1);
+ if (allow_wcards) {
+ status = check_path_syntax_wcard(pdp->reqpath, p, ppath_contains_wcard);
+ } else {
+ status = check_path_syntax(pdp->reqpath, p);
+ }
}
- DEBUG(10,("parse_processed_dfs_path: rest of the path: %s\n",pdp->reqpath));
- return True;
+ 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;
}
/********************************************************
@@ -133,7 +170,7 @@ static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path *pdp, BOOL
Note this CHANGES CWD !!!! JRA.
*********************************************************/
-static BOOL create_conn_struct(connection_struct *conn, int snum, char *path)
+static BOOL create_conn_struct(connection_struct *conn, int snum, const char *path)
{
pstring connpath;
@@ -143,19 +180,19 @@ static BOOL create_conn_struct(connection_struct *conn, int snum, char *path)
pstring_sub(connpath , "%S", lp_servicename(snum));
/* needed for smbd_vfs_init() */
-
- if ( (conn->mem_ctx=talloc_init("connection_struct")) == NULL ) {
- DEBUG(0,("talloc_init(connection_struct) failed!\n"));
- return False;
- }
- if (!(conn->params = TALLOC_P(conn->mem_ctx, struct share_params))) {
+ if ((conn->mem_ctx=talloc_init("connection_struct")) == NULL) {
+ DEBUG(0,("talloc_init(connection_struct) failed!\n"));
+ return False;
+ }
+
+ if (!(conn->params = TALLOC_ZERO_P(conn->mem_ctx, struct share_params))) {
DEBUG(0, ("TALLOC failed\n"));
return False;
}
-
+
conn->params->service = snum;
-
+
set_conn_connectpath(conn, connpath);
if (!smbd_vfs_init(conn)) {
@@ -182,11 +219,27 @@ static BOOL create_conn_struct(connection_struct *conn, int snum, char *path)
/**********************************************************************
Parse the contents of a symlink to verify if it is an msdfs referral
- A valid referral is of the form: msdfs:server1\share1,server2\share2
- talloc CTX can be NULL here if preflist and refcount pointers are null.
+ A valid referral is of the form:
+
+ msdfs:server1\share1,server2\share2
+ msdfs:server1\share1\pathname,server2\share2\pathname
+ msdfs:server1/share1,server2/share2
+ msdfs:server1/share1/pathname,server2/share2/pathname.
+
+ Note that the alternate paths returned here must be of the canonicalized
+ form:
+
+ \server\share or
+ \server\share\path\to\file,
+
+ even in posix path mode. This is because we have no knowledge if the
+ server we're referring to understands posix paths.
**********************************************************************/
-static BOOL parse_symlink(TALLOC_CTX *ctx, char *buf, struct referral **preflist, int *refcount)
+static BOOL parse_msdfs_symlink(TALLOC_CTX *ctx,
+ char *target,
+ struct referral **preflist,
+ int *refcount)
{
pstring temp;
char *prot;
@@ -194,45 +247,28 @@ static BOOL parse_symlink(TALLOC_CTX *ctx, char *buf, struct referral **preflist
int count = 0, i;
struct referral *reflist;
- pstrcpy(temp,buf);
-
+ pstrcpy(temp,target);
prot = strtok(temp,":");
- if (!strequal(prot, "msdfs")) {
- return False;
- }
-
- /* No referral list requested. Just yes/no. */
- if (!preflist) {
- return True;
- }
-
- if (!ctx) {
- DEBUG(0,("parse_symlink: logic error. TALLOC_CTX should not be null.\n"));
- return True;
- }
-
/* parse out the alternate paths */
while((count<MAX_REFERRAL_COUNT) &&
((alt_path[count] = strtok(NULL,",")) != NULL)) {
count++;
}
- DEBUG(10,("parse_symlink: count=%d\n", count));
+ DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
- reflist = *preflist = TALLOC_ARRAY(ctx, struct referral, count);
+ reflist = *preflist = TALLOC_ZERO_ARRAY(ctx, struct referral, count);
if(reflist == NULL) {
- DEBUG(0,("parse_symlink: talloc failed!\n"));
+ DEBUG(0,("parse_msdfs_symlink: talloc failed!\n"));
return False;
}
for(i=0;i<count;i++) {
char *p;
- /* replace all /'s in the alternate path by a \ */
- for(p = alt_path[i]; *p && ((p = strchr_m(p,'/'))!=NULL); p++) {
- *p = '\\';
- }
+ /* Canonicalize link target. Replace all /'s in the path by a \ */
+ string_replace(alt_path[i], '/', '\\');
/* Remove leading '\\'s */
p = alt_path[i];
@@ -242,35 +278,29 @@ static BOOL parse_symlink(TALLOC_CTX *ctx, char *buf, struct referral **preflist
pstrcpy(reflist[i].alternate_path, "\\");
pstrcat(reflist[i].alternate_path, p);
+
reflist[i].proximity = 0;
reflist[i].ttl = REFERRAL_TTL;
- DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path));
- }
-
- if(refcount) {
- *refcount = count;
+ DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n", reflist[i].alternate_path));
+ *refcount += 1;
}
return True;
}
/**********************************************************************
- Returns true if the unix path is a valid msdfs symlink
- talloc CTX can be NULL here if reflistp and refcnt pointers are null.
- **********************************************************************/
+ Returns true if the unix path is a valid msdfs symlink and also
+ returns the target string from inside the link.
+**********************************************************************/
-BOOL is_msdfs_link(TALLOC_CTX *ctx, connection_struct *conn, const char *path,
- struct referral **reflistp, int *refcnt,
- SMB_STRUCT_STAT *sbufp)
+BOOL is_msdfs_link(connection_struct *conn,
+ const char *path,
+ pstring link_target,
+ SMB_STRUCT_STAT *sbufp)
{
SMB_STRUCT_STAT st;
- pstring referral;
int referral_len = 0;
- if (!path || !conn) {
- return False;
- }
-
if (sbufp == NULL) {
sbufp = &st;
}
@@ -280,77 +310,59 @@ BOOL is_msdfs_link(TALLOC_CTX *ctx, connection_struct *conn, const char *path,
return False;
}
- if (S_ISLNK(sbufp->st_mode)) {
- /* open the link and read it */
- referral_len = SMB_VFS_READLINK(conn, path, referral, sizeof(pstring)-1);
- if (referral_len == -1) {
- DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno)));
- return False;
- }
+ if (!S_ISLNK(sbufp->st_mode)) {
+ DEBUG(5,("is_msdfs_link: %s is not a link.\n",path));
+ return False;
+ }
- referral[referral_len] = '\0';
- DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral));
- if (parse_symlink(ctx, referral, reflistp, refcnt)) {
- return True;
- }
+ /* open the link and read it */
+ referral_len = SMB_VFS_READLINK(conn, path, link_target, sizeof(pstring)-1);
+ if (referral_len == -1) {
+ DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n",
+ path, strerror(errno)));
+ return False;
}
- return False;
+ link_target[referral_len] = '\0';
+
+ DEBUG(5,("is_msdfs_link: %s -> %s\n",path, link_target));
+
+ if (!strnequal(link_target, "msdfs:", 6)) {
+ return False;
+ }
+ return True;
}
/*****************************************************************
Used by other functions to decide if a dfs path is remote,
-and to get the list of referred locations for that remote path.
+ and to get the list of referred locations for that remote path.
-findfirst_flag: For findfirsts, dfs links themselves are not
-redirected, but paths beyond the links are. For normal smb calls,
-even dfs links need to be redirected.
-
-self_referralp: clients expect a dfs referral for the same share when
-they request referrals for dfs roots on a server.
+ search_flag: For findfirsts, dfs links themselves are not
+ redirected, but paths beyond the links are. For normal smb calls,
+ even dfs links need to be redirected.
-consumedcntp: how much of the dfs path is being redirected. the client
-should try the remaining path on the redirected server.
+ consumedcntp: how much of the dfs path is being redirected. the client
+ should try the remaining path on the redirected server.
-TALLOC_CTX can be NULL here if struct referral **reflistpp, int *refcntp
-are also NULL.
+ If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
+ link redirect are in targetpath.
*****************************************************************/
-static BOOL resolve_dfs_path(TALLOC_CTX *ctx,
- const char *dfspath,
- struct dfs_path *dp,
- connection_struct *conn,
- BOOL search_flag,
- struct referral **reflistpp,
- int *refcntp,
- BOOL *self_referralp,
- int *consumedcntp)
+static NTSTATUS dfs_path_lookup(connection_struct *conn,
+ const char *dfspath, /* Incoming complete dfs path */
+ const struct dfs_path *pdp, /* Parsed out server+share+extrapath. */
+ BOOL search_flag, /* Called from a findfirst ? */
+ int *consumedcntp,
+ pstring targetpath)
{
- pstring localpath;
- int consumed_level = 1;
- char *p;
+ char *p = NULL;
+ char *q = NULL;
SMB_STRUCT_STAT sbuf;
NTSTATUS status;
- pstring reqpath;
- pstring local_dfspath;
-
- if (!dp || !conn) {
- DEBUG(1,("resolve_dfs_path: NULL dfs_path* or NULL connection_struct*!\n"));
- return False;
- }
-
- if (!ctx && (reflistpp || refcntp)) {
- DEBUG(0,("resolve_dfs_path: logic error. TALLOC_CTX must not be NULL.\n"));
- }
-
- if (dp->reqpath[0] == '\0') {
- if (self_referralp) {
- DEBUG(6,("resolve_dfs_path: self-referral. returning False\n"));
- *self_referralp = True;
- }
- return False;
- }
+ pstring localpath;
+ pstring canon_dfspath; /* Canonicalized dfs path. (only '/' components). */
- DEBUG(10,("resolve_dfs_path: Conn path = %s req_path = %s\n", conn->connectpath, dp->reqpath));
+ DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
+ conn->connectpath, pdp->reqpath));
/*
* Note the unix path conversion here we're doing we can
@@ -364,151 +376,188 @@ static BOOL resolve_dfs_path(TALLOC_CTX *ctx,
* think this is needed. JRA.
*/
- pstrcpy(localpath, dp->reqpath);
-
- status = unix_convert(conn, localpath, False, NULL, &sbuf);
+ pstrcpy(localpath, pdp->reqpath);
+ status = unix_convert(conn, localpath, search_flag, NULL, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
- return False;
+ return status;
}
- /* check if need to redirect */
- if (is_msdfs_link(ctx, conn, localpath, reflistpp, refcntp, NULL)) {
- if ( search_flag ) {
- DEBUG(6,("resolve_dfs_path (FindFirst) No redirection "
+ /* Optimization - check if we can redirect the whole path. */
+
+ if (is_msdfs_link(conn, localpath, targetpath, NULL)) {
+ if (search_flag) {
+ DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
"for dfs link %s.\n", dfspath));
- return False;
+ return NT_STATUS_OK;
}
- DEBUG(6,("resolve_dfs_path: %s resolves to a valid Dfs link.\n", dfspath));
+ DEBUG(6,("dfs_path_lookup: %s resolves to a "
+ "valid dfs link %s.\n", dfspath, targetpath));
+
if (consumedcntp) {
*consumedcntp = strlen(dfspath);
}
- return True;
+ return NT_STATUS_PATH_NOT_COVERED;
}
/* Prepare to test only for '/' components in the given path,
- * so replace all '\\' characters with '/'. */
+ * so if a Windows path replace all '\\' characters with '/'.
+ * For a POSIX DFS path we know all separators are already '/'. */
- pstrcpy(local_dfspath, dfspath);
- string_replace(local_dfspath, '\\', '/');
+ pstrcpy(canon_dfspath, dfspath);
+ if (!pdp->posix_path) {
+ string_replace(canon_dfspath, '\\', '/');
+ }
+
+ /*
+ * Redirect if any component in the path is a link.
+ * We do this by walking backwards through the
+ * local path, chopping off the last component
+ * in both the local path and the canonicalized
+ * DFS path. If we hit a DFS link then we're done.
+ */
+
+ p = strrchr_m(localpath, '/');
+ if (consumedcntp) {
+ q = strrchr_m(canon_dfspath, '/');
+ }
- /* redirect if any component in the path is a link */
- pstrcpy(reqpath, localpath);
- p = strrchr_m(reqpath, '/');
while (p) {
*p = '\0';
- pstrcpy(localpath, reqpath);
- if (is_msdfs_link(ctx, conn, localpath, reflistpp, refcntp, NULL)) {
- DEBUG(4, ("resolve_dfs_path: Redirecting %s because parent %s is dfs link\n", dfspath, localpath));
-
- /* To find the path consumed, we truncate the original
- DFS pathname passed to use to remove the last
- component. The length of the resulting string is
- the path consumed
- */
-
+ if (q) {
+ *q = '\0';
+ }
+
+ if (is_msdfs_link(conn, localpath, targetpath, NULL)) {
+ DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
+ "parent %s is dfs link\n", dfspath, localpath));
+
if (consumedcntp) {
- pstring buf;
- pstrcpy(buf, local_dfspath);
- trim_char(buf, '\0', '/');
- for (; consumed_level; consumed_level--) {
- char *q;
- /* We made sure only '/' may be a separator above. */
- q = strrchr_m(buf, '/');
- if (q) {
- *q = 0;
- }
- }
- *consumedcntp = strlen(buf);
- DEBUG(10, ("resolve_dfs_path: Path consumed: %s (%d)\n", buf, *consumedcntp));
+ *consumedcntp = strlen(canon_dfspath);
+ DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
+ "(%d)\n", canon_dfspath, *consumedcntp));
}
-
- return True;
+
+ return NT_STATUS_PATH_NOT_COVERED;
+ }
+
+ /* Step back on the filesystem. */
+ p = strrchr_m(localpath, '/');
+
+ if (consumedcntp) {
+ /* And in the canonicalized dfs path. */
+ q = strrchr_m(canon_dfspath, '/');
}
- p = strrchr_m(reqpath, '/');
- consumed_level++;
}
- return False;
+ return NT_STATUS_OK;
}
/*****************************************************************
- Decides if a dfs pathname should be redirected or not.
- If not, the pathname is converted to a tcon-relative local unix path
-
- search_wcard_flag: this flag performs 2 functions bother related
- to searches. See resolve_dfs_path() and parse_processed_dfs_path()
- for details.
+ Decides if a dfs pathname should be redirected or not.
+ If not, the pathname is converted to a tcon-relative local unix path
+
+ search_wcard_flag: this flag performs 2 functions bother related
+ to searches. See resolve_dfs_path() and parse_dfs_path_XX()
+ for details.
+
+ This function can return NT_STATUS_OK, meaning use the returned path as-is
+ (mapped into a local path).
+ or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
+ any other NT_STATUS error which is a genuine error to be
+ returned to the client.
*****************************************************************/
-static BOOL dfs_redirect( connection_struct *conn, pstring pathname, BOOL search_wcard_flag )
+static NTSTATUS dfs_redirect( connection_struct *conn,
+ pstring dfs_path,
+ BOOL search_wcard_flag,
+ BOOL *ppath_contains_wcard)
{
+ NTSTATUS status;
struct dfs_path dp;
+ pstring targetpath;
- if (!conn || !pathname) {
- return False;
+ status = parse_dfs_path(dfs_path, search_wcard_flag, &dp, ppath_contains_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (dp.reqpath[0] == '\0') {
+ DEBUG(5,("dfs_redirect: self-referral.\n"));
+ return NT_STATUS_OK;
}
- parse_processed_dfs_path(pathname, &dp, search_wcard_flag);
+ /* If dfs pathname for a non-dfs share, convert to tcon-relative
+ path and return OK */
- /* if dfs pathname for a non-dfs share, convert to tcon-relative
- path and return false */
if (!lp_msdfs_root(SNUM(conn))) {
- pstrcpy(pathname, dp.reqpath);
- return False;
+ pstrcpy(dfs_path, dp.reqpath);
+ return NT_STATUS_OK;
}
-
- if ( !( strequal(dp.servicename, lp_servicename(SNUM(conn)))
- || ( strequal(dp.servicename, HOMES_NAME)
- && strequal(lp_servicename(SNUM(conn)), get_current_username()) )) )
- {
- return False;
+
+ /* If it looked like a local path (zero hostname/servicename)
+ * just treat as a tcon-relative path. */
+
+ if (dp.hostname[0] == '\0' && dp.servicename[0] == '\0') {
+ pstrcpy(dfs_path, dp.reqpath);
+ return NT_STATUS_OK;
}
- if (resolve_dfs_path(NULL, pathname, &dp, conn, search_wcard_flag,
- NULL, NULL, NULL, NULL)) {
- DEBUG(3,("dfs_redirect: Redirecting %s\n", pathname));
- return True;
- } else {
- DEBUG(3,("dfs_redirect: Not redirecting %s.\n", pathname));
+ if (!( strequal(dp.servicename, lp_servicename(SNUM(conn)))
+ || (strequal(dp.servicename, HOMES_NAME)
+ && strequal(lp_servicename(SNUM(conn)), get_current_username()) )) ) {
- /* Form non-dfs tcon-relative path */
- pstrcpy(pathname, dp.reqpath);
+ /* The given sharename doesn't match this connection. */
- DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n", pathname));
- return False;
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ status = dfs_path_lookup(conn, dfs_path, &dp,
+ search_wcard_flag, NULL, targetpath);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
+ DEBUG(3,("dfs_redirect: Redirecting %s\n", dfs_path));
+ } else {
+ DEBUG(10,("dfs_redirect: dfs_path_lookup failed for %s with %s\n",
+ dfs_path, nt_errstr(status) ));
+ }
+ return status;
}
- /* never reached */
+ DEBUG(3,("dfs_redirect: Not redirecting %s.\n", dfs_path));
+
+ /* Form non-dfs tcon-relative path */
+ pstrcpy(dfs_path, dp.reqpath);
+
+ DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n", dfs_path));
+ return NT_STATUS_OK;
}
/**********************************************************************
Return a self referral.
**********************************************************************/
-static BOOL self_ref(TALLOC_CTX *ctx, const char *pathname, struct junction_map *jucn,
- int *consumedcntp, BOOL *self_referralp)
+static BOOL self_ref(TALLOC_CTX *ctx,
+ const char *dfs_path,
+ struct junction_map *jucn,
+ int *consumedcntp,
+ BOOL *self_referralp)
{
struct referral *ref;
- if (self_referralp != NULL) {
- *self_referralp = True;
- }
+ *self_referralp = True;
jucn->referral_count = 1;
- if((ref = TALLOC_P(ctx, struct referral)) == NULL) {
- DEBUG(0,("self_ref: malloc failed for referral\n"));
+ if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
+ DEBUG(0,("self_ref: talloc failed for referral\n"));
return False;
}
- pstrcpy(ref->alternate_path,pathname);
+ pstrcpy(ref->alternate_path,dfs_path);
ref->proximity = 0;
ref->ttl = REFERRAL_TTL;
jucn->referral_list = ref;
- if (consumedcntp) {
- *consumedcntp = strlen(pathname);
- }
-
+ *consumedcntp = strlen(dfs_path);
return True;
}
@@ -517,40 +566,39 @@ static BOOL self_ref(TALLOC_CTX *ctx, const char *pathname, struct junction_map
junction_map structure.
**********************************************************************/
-BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_map *jucn,
- int *consumedcntp, BOOL *self_referralp)
+BOOL get_referred_path(TALLOC_CTX *ctx,
+ const char *dfs_path,
+ struct junction_map *jucn,
+ int *consumedcntp,
+ BOOL *self_referralp)
{
- struct dfs_path dp;
-
struct connection_struct conns;
struct connection_struct *conn = &conns;
+ struct dfs_path dp;
pstring conn_path;
+ pstring targetpath;
int snum;
+ NTSTATUS status;
BOOL ret = False;
- BOOL self_referral = False;
-
- if (!pathname || !jucn) {
- return False;
- }
+ BOOL dummy;
ZERO_STRUCT(conns);
- if (self_referralp) {
- *self_referralp = False;
- } else {
- self_referralp = &self_referral;
- }
+ *self_referralp = False;
- parse_dfs_path(pathname, &dp);
+ status = parse_dfs_path(dfs_path, False, &dp, &dummy);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
/* Verify hostname in path */
if (!is_myname_or_ipaddr(dp.hostname)) {
DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n",
- dp.hostname, pathname));
+ dp.hostname, dfs_path));
return False;
}
- pstrcpy(jucn->service_name, dp.servicename);
+ fstrcpy(jucn->service_name, dp.servicename);
pstrcpy(jucn->volume_name, dp.reqpath);
/* Verify the share is a dfs root */
@@ -562,8 +610,8 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma
}
if (!lp_msdfs_root(snum)) {
- DEBUG(3,("get_referred_path: .%s. in dfs path %s is not a dfs root.\n",
- dp.servicename, pathname));
+ DEBUG(3,("get_referred_path: |%s| in dfs path %s is not a dfs root.\n",
+ dp.servicename, dfs_path));
goto out;
}
@@ -575,15 +623,23 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma
*/
if (dp.reqpath[0] == '\0') {
-
- struct referral* ref;
+ struct referral *ref;
if (*lp_msdfs_proxy(snum) == '\0') {
- return self_ref(ctx, pathname, jucn, consumedcntp, self_referralp);
+ return self_ref(ctx,
+ dfs_path,
+ jucn,
+ consumedcntp,
+ self_referralp);
}
+ /*
+ * It's an msdfs proxy share. Redirect to
+ * the configured target share.
+ */
+
jucn->referral_count = 1;
- if ((ref = TALLOC_P(ctx, struct referral)) == NULL) {
+ if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
DEBUG(0, ("malloc failed for referral\n"));
goto out;
}
@@ -595,9 +651,7 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma
ref->proximity = 0;
ref->ttl = REFERRAL_TTL;
jucn->referral_list = ref;
- if (consumedcntp) {
- *consumedcntp = strlen(pathname);
- }
+ *consumedcntp = strlen(dfs_path);
ret = True;
goto out;
}
@@ -607,23 +661,27 @@ BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_ma
return False;
}
- /* If not remote & not a self referral, return False */
- if (!resolve_dfs_path(ctx, pathname, &dp, conn, False,
- &jucn->referral_list, &jucn->referral_count,
- self_referralp, consumedcntp)) {
- if (!*self_referralp) {
- DEBUG(3,("get_referred_path: No valid referrals for path %s\n", pathname));
- goto out;
- }
+ /* If this is a DFS path dfs_lookup should return
+ * NT_STATUS_PATH_NOT_COVERED. */
+
+ status = dfs_path_lookup(conn, dfs_path, &dp,
+ False, consumedcntp, targetpath);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
+ DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
+ dfs_path));
+ goto out;
}
-
- /* if self_referral, fill up the junction map */
- if (*self_referralp) {
- if (self_ref(ctx, pathname, jucn, consumedcntp, self_referralp) == False) {
- goto out;
- }
+
+ /* We know this is a valid dfs link. Parse the targetpath. */
+ if (!parse_msdfs_symlink(ctx, targetpath,
+ &jucn->referral_list,
+ &jucn->referral_count)) {
+ DEBUG(3,("get_referred_path: failed to parse symlink "
+ "target %s\n", targetpath ));
+ goto out;
}
-
+
ret = True;
out:
@@ -632,10 +690,11 @@ out:
return ret;
}
-static int setup_ver2_dfs_referral(char *pathname, char **ppdata,
- struct junction_map *junction,
- int consumedcnt,
- BOOL self_referral)
+static int setup_ver2_dfs_referral(const char *pathname,
+ char **ppdata,
+ struct junction_map *junction,
+ int consumedcnt,
+ BOOL self_referral)
{
char* pdata = *ppdata;
@@ -647,7 +706,7 @@ static int setup_ver2_dfs_referral(char *pathname, char **ppdata,
int reply_size = 0;
int i=0;
- DEBUG(10,("setting up version2 referral\nRequested path:\n"));
+ DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
requestedpathlen = rpcstr_push(uni_requestedpath, pathname, sizeof(pstring),
STR_TERMINATE);
@@ -681,7 +740,7 @@ static int setup_ver2_dfs_referral(char *pathname, char **ppdata,
pdata = (char *)SMB_REALLOC(pdata,reply_size);
if(pdata == NULL) {
- DEBUG(0,("malloc failed for Realloc!\n"));
+ DEBUG(0,("Realloc failed!\n"));
return -1;
}
*ppdata = pdata;
@@ -732,10 +791,11 @@ static int setup_ver2_dfs_referral(char *pathname, char **ppdata,
return reply_size;
}
-static int setup_ver3_dfs_referral(char *pathname, char **ppdata,
- struct junction_map *junction,
- int consumedcnt,
- BOOL self_referral)
+static int setup_ver3_dfs_referral(const char *pathname,
+ char **ppdata,
+ struct junction_map *junction,
+ int consumedcnt,
+ BOOL self_referral)
{
char* pdata = *ppdata;
@@ -816,17 +876,23 @@ static int setup_ver3_dfs_referral(char *pathname, char **ppdata,
}
/******************************************************************
- Set up the Dfs referral for the dfs pathname
+ Set up the DFS referral for the dfs pathname. This call returns
+ the amount of the path covered by this server, and where the
+ client should be redirected to. This is the meat of the
+ TRANS2_GET_DFS_REFERRAL call.
******************************************************************/
-int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_referral_level, char **ppdata)
+int setup_dfs_referral(connection_struct *orig_conn,
+ const char *dfs_path,
+ int max_referral_level,
+ char **ppdata)
{
struct junction_map junction;
- int consumedcnt;
+ int consumedcnt = 0;
BOOL self_referral = False;
- pstring buf;
int reply_size = 0;
- char *pathnamep = pathname;
+ char *pathnamep = NULL;
+ pstring local_dfs_path;
TALLOC_CTX *ctx;
if (!(ctx=talloc_init("setup_dfs_referral"))) {
@@ -836,21 +902,24 @@ int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_ref
ZERO_STRUCT(junction);
/* get the junction entry */
- if (!pathnamep) {
+ if (!dfs_path) {
talloc_destroy(ctx);
return -1;
}
- /* Trim pathname sent by client so it begins with only one backslash.
- Two backslashes confuse some dfs clients
+ /*
+ * Trim pathname sent by client so it begins with only one backslash.
+ * Two backslashes confuse some dfs clients
*/
- while (pathnamep[0] == '\\' && pathnamep[1] == '\\') {
+
+ pstrcpy(local_dfs_path, dfs_path);
+ pathnamep = local_dfs_path;
+ while (IS_DIRECTORY_SEP(pathnamep[0]) && IS_DIRECTORY_SEP(pathnamep[1])) {
pathnamep++;
}
- pstrcpy(buf, pathnamep);
/* The following call can change cwd. */
- if (!get_referred_path(ctx, buf, &junction, &consumedcnt, &self_referral)) {
+ if (!get_referred_path(ctx, pathnamep, &junction, &consumedcnt, &self_referral)) {
vfs_ChDir(orig_conn,orig_conn->connectpath);
talloc_destroy(ctx);
return -1;
@@ -908,31 +977,40 @@ int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_ref
**********************************************************************/
/*********************************************************************
- Creates a junction structure from a Dfs pathname
+ Creates a junction structure from a DFS pathname
**********************************************************************/
-BOOL create_junction(const char *pathname, struct junction_map *jucn)
+BOOL create_junction(const char *dfs_path, struct junction_map *jucn)
{
- struct dfs_path dp;
+ int snum;
+ BOOL dummy;
+ struct dfs_path dp;
- parse_dfs_path(pathname,&dp);
+ NTSTATUS status = parse_dfs_path(dfs_path, False, &dp, &dummy);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
- /* check if path is dfs : validate first token */
+ /* check if path is dfs : validate first token */
if (!is_myname_or_ipaddr(dp.hostname)) {
DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n",
- dp.hostname, pathname));
+ dp.hostname, dfs_path));
return False;
}
/* Check for a non-DFS share */
- if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
- DEBUG(4,("create_junction: %s is not an msdfs root.\n", dp.servicename));
+ snum = lp_servicenumber(dp.servicename);
+
+ if(snum < 0 || !lp_msdfs_root(snum)) {
+ DEBUG(4,("create_junction: %s is not an msdfs root.\n",
+ dp.servicename));
return False;
}
- pstrcpy(jucn->service_name,dp.servicename);
+ fstrcpy(jucn->service_name,dp.servicename);
pstrcpy(jucn->volume_name,dp.reqpath);
- pstrcpy(jucn->comment, lp_comment(lp_servicenumber(dp.servicename)));
+ pstrcpy(jucn->comment, lp_comment(snum));
return True;
}
@@ -940,16 +1018,14 @@ BOOL create_junction(const char *pathname, struct junction_map *jucn)
Forms a valid Unix pathname from the junction
**********************************************************************/
-static BOOL junction_to_local_path(struct junction_map *jucn, char *path,
- int max_pathlen, connection_struct *conn)
+static BOOL junction_to_local_path(struct junction_map *jucn,
+ char *path,
+ int max_pathlen,
+ connection_struct *conn_out)
{
int snum;
pstring conn_path;
- if(!path || !jucn) {
- return False;
- }
-
snum = lp_servicenumber(jucn->service_name);
if(snum < 0) {
return False;
@@ -960,7 +1036,7 @@ static BOOL junction_to_local_path(struct junction_map *jucn, char *path,
safe_strcat(path, jucn->volume_name, max_pathlen-1);
pstrcpy(conn_path, lp_pathname(snum));
- if (!create_conn_struct(conn, snum, conn_path)) {
+ if (!create_conn_struct(conn_out, snum, conn_path)) {
return False;
}
@@ -983,11 +1059,12 @@ BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists)
return False;
}
- /* form the msdfs_link contents */
+ /* Form the msdfs_link contents */
pstrcpy(msdfs_link, "msdfs:");
for(i=0; i<jucn->referral_count; i++) {
char* refpath = jucn->referral_list[i].alternate_path;
+ /* Alternate paths always use Windows separators. */
trim_char(refpath, '\\', '\\');
if(*refpath == '\0') {
if (i == 0) {
@@ -1005,7 +1082,8 @@ BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists)
}
}
- DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
+ DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
+ path, msdfs_link));
if(exists) {
if(SMB_VFS_UNLINK(conn,path)!=0) {
@@ -1021,7 +1099,7 @@ BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists)
ret = True;
-
+
out:
conn_free_internal(conn);
@@ -1048,13 +1126,16 @@ BOOL remove_msdfs_link(struct junction_map *jucn)
return ret;
}
-static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn, int jn_remain)
+static int form_junctions(TALLOC_CTX *ctx,
+ int snum,
+ struct junction_map *jucn,
+ int jn_remain)
{
int cnt = 0;
SMB_STRUCT_DIR *dirp;
- char* dname;
+ char *dname;
pstring connect_path;
- char* service_name = lp_servicename(snum);
+ char *service_name = lp_servicename(snum);
connection_struct conn;
struct referral *ref = NULL;
@@ -1082,13 +1163,13 @@ static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn,
DO NOT REMOVE THIS: NT clients will not work with us
if this is not present
*/
- pstrcpy(jucn[cnt].service_name, service_name);
+ fstrcpy(jucn[cnt].service_name, service_name);
jucn[cnt].volume_name[0] = '\0';
jucn[cnt].referral_count = 1;
- ref = jucn[cnt].referral_list = TALLOC_P(ctx, struct referral);
+ ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
if (jucn[cnt].referral_list == NULL) {
- DEBUG(0, ("Malloc failed!\n"));
+ DEBUG(0, ("talloc failed!\n"));
goto out;
}
@@ -1099,9 +1180,10 @@ static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn,
cnt++;
goto out;
}
-
- slprintf(ref->alternate_path, sizeof(pstring)-1,
- "\\\\%s\\%s", get_local_machine_name(), service_name);
+
+ pstr_sprintf(ref->alternate_path, "\\\\%s\\%s",
+ get_local_machine_name(),
+ service_name);
cnt++;
/* Now enumerate all dfs links */
@@ -1111,16 +1193,22 @@ static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn,
}
while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
+ pstring link_target;
if (cnt >= jn_remain) {
SMB_VFS_CLOSEDIR(&conn,dirp);
DEBUG(2, ("ran out of MSDFS junction slots"));
goto out;
}
- if (is_msdfs_link(ctx, &conn, dname, &jucn[cnt].referral_list,
- &jucn[cnt].referral_count, NULL)) {
- pstrcpy(jucn[cnt].service_name, service_name);
- pstrcpy(jucn[cnt].volume_name, dname);
- cnt++;
+ if (is_msdfs_link(&conn, dname, link_target, NULL)) {
+ if (parse_msdfs_symlink(ctx,
+ link_target,
+ &jucn[cnt].referral_list,
+ &jucn[cnt].referral_count)) {
+
+ fstrcpy(jucn[cnt].service_name, service_name);
+ pstrcpy(jucn[cnt].volume_name, dname);
+ cnt++;
+ }
}
}
@@ -1160,13 +1248,14 @@ int enum_msdfs_links(TALLOC_CTX *ctx, struct junction_map *jucn, int jn_max)
Core function to resolve a dfs pathname.
******************************************************************************/
-BOOL resolve_dfspath(connection_struct *conn, BOOL dfs_pathnames, pstring name)
+NTSTATUS resolve_dfspath(connection_struct *conn, BOOL dfs_pathnames, pstring name)
{
- if (dfs_pathnames && lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
- dfs_redirect(conn, name, False)) {
- return False; /* Pathname didn't resolve. */
+ NTSTATUS status = NT_STATUS_OK;
+ BOOL dummy;
+ if (dfs_pathnames && lp_host_msdfs() && lp_msdfs_root(SNUM(conn))) {
+ status = dfs_redirect(conn, name, False, &dummy);
}
- return True;
+ return status;
}
/******************************************************************************
@@ -1176,11 +1265,11 @@ BOOL resolve_dfspath(connection_struct *conn, BOOL dfs_pathnames, pstring name)
we're allowing wildcards and when we're not. JRA.
******************************************************************************/
-BOOL resolve_dfspath_wcard(connection_struct *conn, BOOL dfs_pathnames, pstring name)
+NTSTATUS resolve_dfspath_wcard(connection_struct *conn, BOOL dfs_pathnames, pstring name, BOOL *ppath_contains_wcard)
{
- if (dfs_pathnames && lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
- dfs_redirect(conn, name, True)) {
- return False; /* Pathname didn't resolve. */
+ NTSTATUS status = NT_STATUS_OK;
+ if (dfs_pathnames && lp_host_msdfs() && lp_msdfs_root(SNUM(conn))) {
+ status = dfs_redirect(conn, name, True, ppath_contains_wcard);
}
- return True;
+ return status;
}
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 0cc7193170..0ecb14f9c7 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -615,9 +615,13 @@ int reply_ntcreate_and_X(connection_struct *conn,
* Now contruct the smb_open_mode value from the filename,
* desired access and the share access.
*/
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname)) {
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntcreateX);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
@@ -1273,8 +1277,12 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
new_file_attributes = set_posix_case_semantics(conn, file_attributes);
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname)) {
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
status = unix_convert(conn, fname, False, NULL, &sbuf);
@@ -1754,13 +1762,22 @@ int reply_ntrename(connection_struct *conn,
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, oldname)) {
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, oldname);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntrename);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname)) {
+
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntrename);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
DEBUG(3,("reply_ntrename : %s -> %s\n",oldname,newname));
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 225e0e7407..c0a2e23c3d 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -44,9 +44,12 @@ extern BOOL global_encrypted_passwords_negotiated;
set.
****************************************************************************/
+/* Custom version for processing POSIX paths. */
+#define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
+
NTSTATUS check_path_syntax_internal(pstring destname,
const pstring srcname,
- BOOL windows_path,
+ BOOL posix_path,
BOOL *p_last_component_contains_wcard)
{
char *d = destname;
@@ -57,13 +60,13 @@ NTSTATUS check_path_syntax_internal(pstring destname,
*p_last_component_contains_wcard = False;
while (*s) {
- if (IS_DIRECTORY_SEP(*s)) {
+ if (IS_PATH_SEP(*s,posix_path)) {
/*
* Safe to assume is not the second part of a mb char
* as this is handled below.
*/
/* Eat multiple '/' or '\\' */
- while (IS_DIRECTORY_SEP(*s)) {
+ while (IS_PATH_SEP(*s,posix_path)) {
s++;
}
if ((d != destname) && (*s != '\0')) {
@@ -78,7 +81,7 @@ NTSTATUS check_path_syntax_internal(pstring destname,
}
if (start_of_name_component) {
- if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) {
+ if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
/* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
/*
@@ -108,8 +111,8 @@ NTSTATUS check_path_syntax_internal(pstring destname,
/* We're still at the start of a name component, just the previous one. */
continue;
- } else if ((s[0] == '.') && ((s[1] == '\0') || IS_DIRECTORY_SEP(s[1]))) {
- if (!windows_path) {
+ } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
+ if (posix_path) {
/* Eat the '.' */
s++;
continue;
@@ -119,7 +122,7 @@ NTSTATUS check_path_syntax_internal(pstring destname,
}
if (!(*s & 0x80)) {
- if (windows_path) {
+ if (!posix_path) {
if (*s <= 0x1f) {
return NT_STATUS_OBJECT_NAME_INVALID;
}
@@ -177,7 +180,7 @@ NTSTATUS check_path_syntax_internal(pstring destname,
NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
{
BOOL ignore;
- return check_path_syntax_internal(destname, srcname, True, &ignore);
+ return check_path_syntax_internal(destname, srcname, False, &ignore);
}
/****************************************************************************
@@ -188,7 +191,7 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard)
{
- return check_path_syntax_internal(destname, srcname, True, p_contains_wcard);
+ return check_path_syntax_internal(destname, srcname, False, p_contains_wcard);
}
/****************************************************************************
@@ -197,10 +200,10 @@ NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *
set (a safe assumption).
****************************************************************************/
-static NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
+NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
{
BOOL ignore;
- return check_path_syntax_internal(destname, srcname, False, &ignore);
+ return check_path_syntax_internal(destname, srcname, True, &ignore);
}
/****************************************************************************
@@ -225,6 +228,16 @@ size_t srvstr_get_path_wcard(char *inbuf, char *dest, const char *src, size_t de
*contains_wcard = False;
+ if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
+ /*
+ * For a DFS path the function parse_dfs_path()
+ * will do the path processing, just make a copy.
+ */
+ pstrcpy(dest, tmppath);
+ *err = NT_STATUS_OK;
+ return ret;
+ }
+
if (lp_posix_pathnames()) {
*err = check_path_syntax_posix(dest, tmppath);
} else {
@@ -252,6 +265,17 @@ size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len
} else {
ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
}
+
+ if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
+ /*
+ * For a DFS path the function parse_dfs_path()
+ * will do the path processing, just make a copy.
+ */
+ pstrcpy(dest, tmppath);
+ *err = NT_STATUS_OK;
+ return ret;
+ }
+
if (lp_posix_pathnames()) {
*err = check_path_syntax_posix(dest, tmppath);
} else {
@@ -632,9 +656,13 @@ int reply_checkpath(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name)) {
- END_PROFILE(SMBcheckpath);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ END_PROFILE(SMBcheckpath);
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ goto path_err;
}
DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(inbuf,smb_vwv0)));
@@ -714,9 +742,13 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname)) {
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBgetatr);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
/* dos smetimes asks for a stat of "" - it returns a "hidden directory"
@@ -796,9 +828,13 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname)) {
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBsetatr);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
status = unix_convert(conn, fname, False, NULL, &sbuf);
@@ -954,9 +990,13 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_NT(nt_status);
}
- if (!resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, path)) {
+ nt_status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, path, &mask_contains_wcard);
+ if (!NT_STATUS_IS_OK(nt_status)) {
END_PROFILE(SMBsearch);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(nt_status);
}
p++;
@@ -1210,9 +1250,13 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname)) {
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBopen);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
status = unix_convert(conn, fname, False, NULL, &sbuf);
@@ -1337,9 +1381,13 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname)) {
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBopenX);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
status = unix_convert(conn, fname, False, NULL, &sbuf);
@@ -1518,9 +1566,13 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname)) {
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcreate);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
status = unix_convert(conn, fname, False, NULL, &sbuf);
@@ -1617,9 +1669,13 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
pstrcat(fname,"TMXXXXXX");
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname)) {
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBctemp);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
status = unix_convert(conn, fname, False, NULL, &sbuf);
@@ -2022,10 +2078,14 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
END_PROFILE(SMBunlink);
return ERROR_NT(status);
}
-
- if (!resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name)) {
+
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &path_contains_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBunlink);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
DEBUG(3,("reply_unlink : %s\n",name));
@@ -3656,9 +3716,13 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory)) {
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmkdir);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
status = unix_convert(conn, directory, False, NULL, &sbuf);
@@ -3877,9 +3941,13 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory)) {
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBrmdir);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
status = unix_convert(conn, directory, False, NULL, &sbuf);
@@ -4632,13 +4700,22 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_NT(status);
}
- if (!resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name)) {
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &src_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmv);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
- if (!resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname)) {
+
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmv);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
@@ -4825,13 +4902,22 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return ERROR_DOS(ERRSRV,ERRinvdevice);
}
- if (!resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name)) {
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &source_has_wild);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcopy);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
- if (!resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname)) {
+
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wild);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcopy);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
status = unix_convert(conn, name, source_has_wild, NULL, &sbuf1);
@@ -5023,9 +5109,13 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newdir)) {
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newdir);
+ if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(pathworks_setdir);
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
if (strlen(newdir) != 0) {
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 58fa4eb31b..deb5db1baf 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -1202,15 +1202,17 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
continue;
}
} else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
+ pstring link_target;
/* Needed to show the msdfs symlinks as
* directories */
if(lp_host_msdfs() &&
lp_msdfs_root(SNUM(conn)) &&
- ((ms_dfs_link = is_msdfs_link(NULL,conn, pathreal, NULL, NULL, &sbuf)) == True)) {
-
- DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal));
+ ((ms_dfs_link = is_msdfs_link(conn, pathreal, link_target, &sbuf)) == True)) {
+ DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s "
+ "as a directory\n",
+ pathreal));
sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR;
} else {
@@ -1727,8 +1729,12 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
return ERROR_NT(ntstatus);
}
- if (!resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory)) {
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ ntstatus = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory, &mask_contains_wcard);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(ntstatus);
}
ntstatus = unix_convert(conn, directory, True, NULL, &sbuf);
@@ -3248,8 +3254,12 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname)) {
- return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
status = unix_convert(conn, fname, False, NULL, &sbuf);
@@ -4376,7 +4386,6 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
pstring rel_name;
char *last_dirp = NULL;
- unix_format(link_target);
if (*link_target == '/') {
/* No absolute paths allowed. */
return NT_STATUS_ACCESS_DENIED;
@@ -4430,8 +4439,9 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
return status;
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, oldname)) {
- return NT_STATUS_PATH_NOT_COVERED;
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, oldname);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
@@ -4478,8 +4488,9 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
return status;
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname)) {
- return NT_STATUS_PATH_NOT_COVERED;
+ status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wcard);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
/* Check the new name has no '/' characters. */
@@ -5647,8 +5658,12 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
return ERROR_NT(status);
}
- if (!resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname)) {
- ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+ return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
+ }
+ return ERROR_NT(status);
}
status = unix_convert(conn, fname, False, NULL, &sbuf);