Check-in the DFS rewrite. I am still testing this but it
authorjra <jra@0c0555d6-39d7-0310-84fc-f1cc0bd64818>
Mon, 12 Mar 2007 17:55:24 +0000 (17:55 +0000)
committerjra <jra@0c0555d6-39d7-0310-84fc-f1cc0bd64818>
Mon, 12 Mar 2007 17:55:24 +0000 (17:55 +0000)
works from smbclient and Windows, and I am promising to
support and fix both client and server code moving forward.
Still need to test the RPC admin support but I haven't
changed that code.
Jeremy.

git-svn-id: svn+ssh://svn.samba.org/data/svn/samba/branches/SAMBA_3_0@21800 0c0555d6-39d7-0310-84fc-f1cc0bd64818

source/include/msdfs.h
source/lib/util.c
source/libsmb/clidfs.c
source/rpc_server/srv_dfs_nt.c
source/smbd/dir.c
source/smbd/msdfs.c
source/smbd/nttrans.c
source/smbd/reply.c
source/smbd/trans2.c

index bf553f4a993bec5f4c2cd93661f39d0daab5e903..05cfe4e102f52732a942e7b99ce418ad19c82ac3 100644 (file)
@@ -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)                      \
index aa8aaa0628b35800f5dbb8f2b47c7e6eaf0d655a..6789a12a1e8bf52ec3b774e7c4fc0b97f79f0763 100644 (file)
@@ -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;
 
index e2cfd121148d452e1d3a3abc3e8c3ef08d6847ed..4009b98b418404bc8920f7b348b658cd02323fb7 100644 (file)
@@ -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_statecli_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 */
        
index 98818826df6951b79cf18448ca03f4d67d7da268..c7adffd62f8360c9e7f6815e014510936c217702 100644 (file)
@@ -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;
 }
-
index 2795b2a24b29fa10e1fdf1ec19a75f0f8bd98135..db3e155ae4783ede8053bc89becba4225ff65796 100644 (file)
@@ -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;
                }
index 861588e6b730ec501e8453819c3203b0727c4d37..ae2009ad380460bbe2de5e64201a4f919e0e7d88 100644 (file)
@@ -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
 
 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;
-       chardname;
+       char *dname;
        pstring connect_path;
-       charservice_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;
 }
index 0cc7193170b20f2748e7f2c3e6e5ace0f3e4bc74..0ecb14f9c76683325aedffcb1385d6ddaa9380f8 100644 (file)
@@ -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));
index 225e0e7407dd5b3934b8227fd565df52c493778c..c0a2e23c3d70c993c59259944d6b87f802af1146 100644 (file)
@@ -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) {
index 58fa4eb31b049cf25f06daddcaad508d41b6f1e1..deb5db1bafea8a0f554f98a83d89ca6849ef0d06 100644 (file)
@@ -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);