summaryrefslogtreecommitdiff
path: root/source3/libsmb/clidfs.c
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2005-02-23 17:29:28 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 10:55:44 -0500
commit01b87c63c90083dbb7a56d038f714bde1a49fb2a (patch)
tree65b73bed578bf66408369425ecc7d47c4d70ab1d /source3/libsmb/clidfs.c
parent96a3fede405cd095e353398ff05f4b43a07c457d (diff)
downloadsamba-01b87c63c90083dbb7a56d038f714bde1a49fb2a.tar.gz
samba-01b87c63c90083dbb7a56d038f714bde1a49fb2a.tar.bz2
samba-01b87c63c90083dbb7a56d038f714bde1a49fb2a.zip
r5518: Add initial msdfs support to smbclient. Currently I can only
cd up and down the tree and get directory listings. Still have to figure out how to get a directory listing on a 2k dfs root. Also have to work out some issues with relative paths that cross dfs mount points. We're protected from the new code paths when connecting to a non-dfs root share ( the flag from the tcon&X is stored in the struct cli_state* ) (This used to be commit e57fd2c5f00de2b11a2b44374830e89a90bc0022)
Diffstat (limited to 'source3/libsmb/clidfs.c')
-rw-r--r--source3/libsmb/clidfs.c257
1 files changed, 229 insertions, 28 deletions
diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c
index bb82fbfabb..ea66eba998 100644
--- a/source3/libsmb/clidfs.c
+++ b/source3/libsmb/clidfs.c
@@ -1,8 +1,8 @@
/*
Unix SMB/CIFS implementation.
client connect/disconnect routines
- Copyright (C) Gerald (Jerry) Carter
-
+ Copyright (C) Gerald (Jerry) Carter 2004
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -22,30 +22,12 @@
#include "includes.h"
-/********************************************************************
- check for dfs referral
-********************************************************************/
-
-BOOL check_for_dfs_referral( struct cli_state *cli )
-{
- uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
-
- /* only deal with DS when we negotiated NT_STATUS codes and UNICODE */
-
- if ( !( (flgs2&FLAGS2_32_BIT_ERROR_CODES) && (flgs2&FLAGS2_UNICODE_STRINGS) ) )
- return False;
-
- if ( NT_STATUS_EQUAL( NT_STATUS_PATH_NOT_COVERED, NT_STATUS(IVAL(cli->inbuf,smb_rcls)) ) )
- return True;
-
- return False;
-}
/********************************************************************
split a dfs path into the server and share name components
********************************************************************/
-void split_dfs_path( const char *nodepath, fstring server, fstring share )
+static void split_dfs_path( const char *nodepath, fstring server, fstring share )
{
char *p;
pstring path;
@@ -67,12 +49,112 @@ void split_dfs_path( const char *nodepath, fstring server, fstring share )
fstrcpy( server, &path[1] );
}
+/****************************************************************************
+ return the original path truncated at the first wildcard character
+ (also strips trailing \'s). Trust the caller to provide a NULL
+ terminated string
+****************************************************************************/
+
+static void clean_path( pstring clean, const char *path )
+{
+ int len;
+ char *p;
+ pstring newpath;
+
+ pstrcpy( newpath, path );
+ p = newpath;
+
+ while ( p ) {
+ /* first check for '*' */
+
+ p = strrchr_m( newpath, '*' );
+ if ( p ) {
+ *p = '\0';
+ p = newpath;
+ continue;
+ }
+
+ /* first check for '?' */
+
+ p = strrchr_m( newpath, '?' );
+ if ( p ) {
+ *p = '\0';
+ p = newpath;
+ }
+ }
+
+ /* strip a trailing backslash */
+
+ len = strlen( newpath );
+ if ( newpath[len-1] == '\\' )
+ newpath[len-1] = '\0';
+
+ pstrcpy( clean, newpath );
+}
+
+/****************************************************************************
+****************************************************************************/
+
+static BOOL make_full_path( pstring path, const char *server, const char *share,
+ const char *dir )
+{
+ 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++;
+ }
+
+ directory = dir;
+ if ( *directory == '\\' )
+ directory++;
+
+ pstr_sprintf( path, "\\%s\\%s\\%s", server, sharename, directory );
+
+ return True;
+}
+
+/********************************************************************
+ check for dfs referral
+********************************************************************/
+
+static BOOL cli_dfs_check_error( struct cli_state *cli )
+{
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ /* only deal with DS when we negotiated NT_STATUS codes and UNICODE */
+
+ if ( !( (flgs2&FLAGS2_32_BIT_ERROR_CODES) && (flgs2&FLAGS2_UNICODE_STRINGS) ) )
+ return False;
+
+ if ( NT_STATUS_EQUAL( NT_STATUS_PATH_NOT_COVERED, NT_STATUS(IVAL(cli->inbuf,smb_rcls)) ) )
+ return True;
+
+ return False;
+}
+
/********************************************************************
get the dfs referral link
********************************************************************/
BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
- struct referral **refs, size_t *num_refs)
+ CLIENT_DFS_REFERRAL**refs, size_t *num_refs,
+ uint16 *consumed)
{
unsigned int data_len = 0;
unsigned int param_len = 0;
@@ -83,7 +165,7 @@ BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
char *p;
size_t pathlen = 2*(strlen(path)+1);
uint16 num_referrals;
- struct referral *referrals;
+ CLIENT_DFS_REFERRAL *referrals;
memset(param, 0, sizeof(param));
SSVAL(param, 0, 0x03); /* max referral level */
@@ -108,6 +190,7 @@ BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
return False;
}
+ *consumed = SVAL( rdata, 0 );
num_referrals = SVAL( rdata, 2 );
if ( num_referrals != 0 ) {
@@ -117,7 +200,7 @@ BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
uint16 node_offset;
- referrals = SMB_XMALLOC_ARRAY( struct referral, num_referrals );
+ referrals = SMB_XMALLOC_ARRAY( CLIENT_DFS_REFERRAL, num_referrals );
/* start at the referrals array */
@@ -132,11 +215,11 @@ BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
continue;
}
- referrals[0].proximity = SVAL( p, 8 );
- referrals[0].ttl = SVAL( p, 10 );
+ referrals[i].proximity = SVAL( p, 8 );
+ referrals[i].ttl = SVAL( p, 10 );
- clistr_pull( cli, referrals[0].alternate_path, p+node_offset,
- sizeof(referrals[0].alternate_path), -1, STR_TERMINATE|STR_UNICODE );
+ clistr_pull( cli, referrals[i].dfspath, p+node_offset,
+ sizeof(referrals[i].dfspath), -1, STR_TERMINATE|STR_UNICODE );
p += ref_size;
}
@@ -152,3 +235,121 @@ BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
return True;
}
+#if 0
+/********************************************************************
+********************************************************************/
+
+BOOL cli_dfs_handle_referral( struct cli_state *cli, const char *path )
+{
+ struct cli_state *cli_ipc;
+ pstring fullpath;
+ CLIENT_DFS_REFERRAL *refs = NULL;
+ size_t num_refs;
+ uint16 consumed;
+ fstring server, share;
+
+ if ( !cli_dfs_check_error(cli) )
+ return False;
+
+ if ( !(cli_ipc = cli_cm_open( cli->desthost, "IPC$", False )) )
+ return False;
+
+ make_full_path( fullpath, cli->desthost, cli->share, path );
+
+ if ( !cli_dfs_get_referral( cli_ipc, fullpath, &refs, &num_refs, &consumed ) ) {
+ d_printf("cli_get_dfs_referral() failed!\n");
+ /* reset the current client connection */
+ cli_cm_open( cli->desthost, cli->share, False );
+
+ return False;
+ }
+
+ /* just pick the first one */
+ if ( num_refs ) {
+ split_dfs_path( refs[0].alternate_path, server, share );
+ if ( cli_cm_open( server, share, False ) == NULL ) {
+ d_printf("Unable to follow dfs referral [\\\\%s\\%s]\n",
+ server, share );
+ cli_cm_open( cli->desthost, cli->share, False );
+
+ return False;
+ }
+ }
+
+ SAFE_FREE( refs );
+
+ return True;
+}
+#endif
+
+/********************************************************************
+********************************************************************/
+
+BOOL cli_resolve_path( 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;
+ int pathlen;
+ fstring server, share;
+
+ SMB_STRUCT_STAT sbuf;
+ uint32 attributes;
+
+ if ( !rootcli || !path || !targetcli )
+ return False;
+
+ /* send a trans2_query_path_info to check for a referral */
+
+ clean_path( cleanpath, path );
+ make_full_path( fullpath, rootcli->desthost, rootcli->share, cleanpath );
+
+ /* don't bother continuing if this is not a dfs root */
+
+ if ( !rootcli->dfsroot || cli_qpathinfo_basic( rootcli, fullpath, &sbuf, &attributes ) ) {
+ *targetcli = rootcli;
+ pstrcpy( targetpath, path );
+ return True;
+ }
+
+ /* we got an error, check for DFS referral */
+
+ if ( !cli_dfs_check_error(rootcli) )
+ return False;
+
+ /* 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)
+ || !num_refs )
+ {
+ return False;
+ }
+
+ /* just store the first referral for now
+ Make sure to recreate the original string including any wildcards */
+
+ make_full_path( fullpath, rootcli->desthost, rootcli->share, path );
+ pathlen = strlen( fullpath )*2;
+ consumed = MIN(pathlen, consumed );
+ pstrcpy( targetpath, &fullpath[consumed/2] );
+
+ split_dfs_path( refs[0].dfspath, server, share );
+ SAFE_FREE( refs );
+
+ /* open the connection to the target path */
+
+ if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) {
+ d_printf("Unable to follow dfs referral [//%s/%s]\n",
+ server, share );
+
+ return False;
+ }
+
+ return True;
+}