2 Unix SMB/CIFS implementation.
3 client connect/disconnect routines
4 Copyright (C) Gerald (Jerry) Carter 2004
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /********************************************************************
27 split a dfs path into the server and share name components
28 ********************************************************************/
30 static void split_dfs_path( const char *nodepath, fstring server, fstring share )
35 pstrcpy( path, nodepath );
37 if ( path[0] != '\\' )
40 p = strrchr_m( path, '\\' );
49 fstrcpy( server, &path[1] );
52 /****************************************************************************
53 return the original path truncated at the first wildcard character
54 (also strips trailing \'s). Trust the caller to provide a NULL
56 ****************************************************************************/
58 static void clean_path( pstring clean, const char *path )
64 pstrcpy( newpath, path );
68 /* first check for '*' */
70 p = strrchr_m( newpath, '*' );
77 /* first check for '?' */
79 p = strrchr_m( newpath, '?' );
86 /* strip a trailing backslash */
88 len = strlen( newpath );
89 if ( newpath[len-1] == '\\' )
90 newpath[len-1] = '\0';
92 pstrcpy( clean, newpath );
95 /****************************************************************************
96 ****************************************************************************/
98 static BOOL make_full_path( pstring path, const char *server, const char *share,
103 const char *directory;
106 /* make a copy so we don't modify the global string 'service' */
108 pstrcpy(servicename, share);
109 sharename = servicename;
111 if (*sharename == '\\') {
113 server = sharename+2;
114 sharename = strchr_m(server,'\\');
124 if ( *directory == '\\' )
127 pstr_sprintf( path, "\\%s\\%s\\%s", server, sharename, directory );
132 /********************************************************************
133 check for dfs referral
134 ********************************************************************/
136 static BOOL cli_dfs_check_error( struct cli_state *cli )
138 uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
140 /* only deal with DS when we negotiated NT_STATUS codes and UNICODE */
142 if ( !( (flgs2&FLAGS2_32_BIT_ERROR_CODES) && (flgs2&FLAGS2_UNICODE_STRINGS) ) )
145 if ( NT_STATUS_EQUAL( NT_STATUS_PATH_NOT_COVERED, NT_STATUS(IVAL(cli->inbuf,smb_rcls)) ) )
151 /********************************************************************
152 get the dfs referral link
153 ********************************************************************/
155 BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path,
156 CLIENT_DFS_REFERRAL**refs, size_t *num_refs,
159 unsigned int data_len = 0;
160 unsigned int param_len = 0;
161 uint16 setup = TRANSACT2_GET_DFS_REFERRAL;
162 char param[sizeof(pstring)+2];
164 char *rparam=NULL, *rdata=NULL;
166 size_t pathlen = 2*(strlen(path)+1);
167 uint16 num_referrals;
168 CLIENT_DFS_REFERRAL *referrals;
170 memset(param, 0, sizeof(param));
171 SSVAL(param, 0, 0x03); /* max referral level */
174 p += clistr_push(cli, p, path, MIN(pathlen, sizeof(param)-2), STR_TERMINATE);
175 param_len = PTR_DIFF(p, param);
177 if (!cli_send_trans(cli, SMBtrans2,
179 -1, 0, /* fid, flags */
180 &setup, 1, 0, /* setup, length, max */
181 param, param_len, 2, /* param, length, max */
182 (char *)&data, data_len, cli->max_xmit /* data, length, max */
187 if (!cli_receive_trans(cli, SMBtrans2,
189 &rdata, &data_len)) {
193 *consumed = SVAL( rdata, 0 );
194 num_referrals = SVAL( rdata, 2 );
196 if ( num_referrals != 0 ) {
203 referrals = SMB_XMALLOC_ARRAY( CLIENT_DFS_REFERRAL, num_referrals );
205 /* start at the referrals array */
208 for ( i=0; i<num_referrals; i++ ) {
209 ref_version = SVAL( p, 0 );
210 ref_size = SVAL( p, 2 );
211 node_offset = SVAL( p, 16 );
213 if ( ref_version != 3 ) {
218 referrals[i].proximity = SVAL( p, 8 );
219 referrals[i].ttl = SVAL( p, 10 );
221 clistr_pull( cli, referrals[i].dfspath, p+node_offset,
222 sizeof(referrals[i].dfspath), -1, STR_TERMINATE|STR_UNICODE );
229 *num_refs = num_referrals;
238 /********************************************************************
239 ********************************************************************/
241 BOOL cli_resolve_path( struct cli_state *rootcli, const char *path,
242 struct cli_state **targetcli, pstring targetpath )
244 CLIENT_DFS_REFERRAL *refs = NULL;
247 struct cli_state *cli_ipc;
248 pstring fullpath, cleanpath;
250 fstring server, share;
251 struct cli_state *newcli;
254 SMB_STRUCT_STAT sbuf;
257 if ( !rootcli || !path || !targetcli )
260 /* send a trans2_query_path_info to check for a referral */
262 clean_path( cleanpath, path );
263 make_full_path( fullpath, rootcli->desthost, rootcli->share, cleanpath );
265 /* don't bother continuing if this is not a dfs root */
267 if ( !rootcli->dfsroot || cli_qpathinfo_basic( rootcli, fullpath, &sbuf, &attributes ) ) {
268 *targetcli = rootcli;
269 pstrcpy( targetpath, path );
273 /* we got an error, check for DFS referral */
275 if ( !cli_dfs_check_error(rootcli) )
278 /* check for the referral */
280 if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) )
283 if ( !cli_dfs_get_referral(cli_ipc, fullpath, &refs, &num_refs, &consumed)
289 /* just store the first referral for now
290 Make sure to recreate the original string including any wildcards */
292 make_full_path( fullpath, rootcli->desthost, rootcli->share, path );
293 pathlen = strlen( fullpath )*2;
294 consumed = MIN(pathlen, consumed );
295 pstrcpy( targetpath, &fullpath[consumed/2] );
297 split_dfs_path( refs[0].dfspath, server, share );
300 /* open the connection to the target path */
302 if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) {
303 d_printf("Unable to follow dfs referral [//%s/%s]\n",
309 /* check for another dfs refeerrali, note that we are not
310 checking for loops here */
312 if ( cli_resolve_path( *targetcli, targetpath, &newcli, newpath ) ) {
314 pstrcpy( targetpath, newpath );