diff options
Diffstat (limited to 'source3/libsmb')
-rw-r--r-- | source3/libsmb/cliconnect.c | 2 | ||||
-rw-r--r-- | source3/libsmb/clidfs.c | 154 | ||||
-rw-r--r-- | source3/libsmb/clientgen.c | 4 | ||||
-rw-r--r-- | source3/libsmb/cliprint.c | 105 |
4 files changed, 263 insertions, 2 deletions
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index bffe9dfe8a..fa98d55f25 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -151,7 +151,7 @@ static uint32 cli_session_setup_capabilities(struct cli_state *cli) if (cli->use_level_II_oplocks) capabilities |= CAP_LEVEL_II_OPLOCKS; - capabilities |= (cli->capabilities & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX)); + capabilities |= (cli->capabilities & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS)); return capabilities; } diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c new file mode 100644 index 0000000000..bb82fbfabb --- /dev/null +++ b/source3/libsmb/clidfs.c @@ -0,0 +1,154 @@ +/* + Unix SMB/CIFS implementation. + client connect/disconnect routines + Copyright (C) Gerald (Jerry) Carter + + 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 + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define NO_SYSLOG + +#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 ) +{ + char *p; + pstring path; + + pstrcpy( path, nodepath ); + + if ( path[0] != '\\' ) + return; + + p = strrchr_m( path, '\\' ); + + if ( !p ) + return; + + *p = '\0'; + p++; + + fstrcpy( share, p ); + fstrcpy( server, &path[1] ); +} + +/******************************************************************** + get the dfs referral link +********************************************************************/ + +BOOL cli_dfs_get_referral( struct cli_state *cli, const char *path, + struct referral **refs, size_t *num_refs) +{ + unsigned int data_len = 0; + unsigned int param_len = 0; + uint16 setup = TRANSACT2_GET_DFS_REFERRAL; + char param[sizeof(pstring)+2]; + pstring data; + char *rparam=NULL, *rdata=NULL; + char *p; + size_t pathlen = 2*(strlen(path)+1); + uint16 num_referrals; + struct referral *referrals; + + memset(param, 0, sizeof(param)); + SSVAL(param, 0, 0x03); /* max referral level */ + p = ¶m[2]; + + p += clistr_push(cli, p, path, MIN(pathlen, sizeof(param)-2), STR_TERMINATE); + param_len = PTR_DIFF(p, param); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 2, /* param, length, max */ + (char *)&data, data_len, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + num_referrals = SVAL( rdata, 2 ); + + if ( num_referrals != 0 ) { + uint16 ref_version; + uint16 ref_size; + int i; + uint16 node_offset; + + + referrals = SMB_XMALLOC_ARRAY( struct referral, num_referrals ); + + /* start at the referrals array */ + + p = rdata+8; + for ( i=0; i<num_referrals; i++ ) { + ref_version = SVAL( p, 0 ); + ref_size = SVAL( p, 2 ); + node_offset = SVAL( p, 16 ); + + if ( ref_version != 3 ) { + p += ref_size; + continue; + } + + referrals[0].proximity = SVAL( p, 8 ); + referrals[0].ttl = SVAL( p, 10 ); + + clistr_pull( cli, referrals[0].alternate_path, p+node_offset, + sizeof(referrals[0].alternate_path), -1, STR_TERMINATE|STR_UNICODE ); + + p += ref_size; + } + + } + + *num_refs = num_referrals; + *refs = referrals; + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + + return True; +} + diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 39fe91172d..369fba3521 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -185,6 +185,8 @@ void cli_setup_packet(struct cli_state *cli) flags2 = FLAGS2_LONG_PATH_COMPONENTS; if (cli->capabilities & CAP_UNICODE) flags2 |= FLAGS2_UNICODE_STRINGS; + if (cli->capabilities & CAP_DFS) + flags2 |= FLAGS2_DFS_PATHNAMES; if (cli->capabilities & CAP_STATUS32) flags2 |= FLAGS2_32_BIT_ERROR_CODES; if (cli->use_spnego) @@ -283,7 +285,7 @@ struct cli_state *cli_initialise(struct cli_state *cli) cli->use_spnego = lp_client_use_spnego(); - cli->capabilities = CAP_UNICODE | CAP_STATUS32; + cli->capabilities = CAP_UNICODE | CAP_STATUS32 | CAP_DFS; /* Set the CLI_FORCE_DOSERR environment variable to test client routines using DOS errors instead of STATUS32 diff --git a/source3/libsmb/cliprint.c b/source3/libsmb/cliprint.c index 2fb0e59aca..732241a758 100644 --- a/source3/libsmb/cliprint.c +++ b/source3/libsmb/cliprint.c @@ -156,3 +156,108 @@ int cli_printjob_del(struct cli_state *cli, int job) } +/**************************************************************************** + Open a spool file +****************************************************************************/ + +int cli_spl_open(struct cli_state *cli, const char *fname, int flags, int share_mode) +{ + char *p; + unsigned openfn=0; + unsigned accessmode=0; + + if (flags & O_CREAT) + openfn |= (1<<4); + if (!(flags & O_EXCL)) { + if (flags & O_TRUNC) + openfn |= (1<<1); + else + openfn |= (1<<0); + } + + accessmode = (share_mode<<4); + + if ((flags & O_ACCMODE) == O_RDWR) { + accessmode |= 2; + } else if ((flags & O_ACCMODE) == O_WRONLY) { + accessmode |= 1; + } + +#if defined(O_SYNC) + if ((flags & O_SYNC) == O_SYNC) { + accessmode |= (1<<14); + } +#endif /* O_SYNC */ + + if (share_mode == DENY_FCB) { + accessmode = 0xFF; + } + + memset(cli->outbuf,'\0',smb_size); + memset(cli->inbuf,'\0',smb_size); + + set_message(cli->outbuf,15,0,True); + + SCVAL(cli->outbuf,smb_com,SMBsplopen); + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + SSVAL(cli->outbuf,smb_vwv0,0xFF); + SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */ + SSVAL(cli->outbuf,smb_vwv3,accessmode); + SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN); + SSVAL(cli->outbuf,smb_vwv5,0); + SSVAL(cli->outbuf,smb_vwv8,openfn); + + if (cli->use_oplocks) { + /* if using oplocks then ask for a batch oplock via + core and extended methods */ + SCVAL(cli->outbuf,smb_flg, CVAL(cli->outbuf,smb_flg)| + FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK); + SSVAL(cli->outbuf,smb_vwv2,SVAL(cli->outbuf,smb_vwv2) | 6); + } + + p = smb_buf(cli->outbuf); + p += clistr_push(cli, p, fname, -1, STR_TERMINATE); + + cli_setup_bcc(cli, p); + + cli_send_smb(cli); + if (!cli_receive_smb(cli)) { + return -1; + } + + if (cli_is_error(cli)) { + return -1; + } + + return SVAL(cli->inbuf,smb_vwv2); +} + +/**************************************************************************** + Close a file. +****************************************************************************/ + +BOOL cli_spl_close(struct cli_state *cli, int fnum) +{ + memset(cli->outbuf,'\0',smb_size); + memset(cli->inbuf,'\0',smb_size); + + set_message(cli->outbuf,3,0,True); + + SCVAL(cli->outbuf,smb_com,SMBsplclose); + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + SSVAL(cli->outbuf,smb_vwv0,fnum); + SIVALS(cli->outbuf,smb_vwv1,-1); + + cli_send_smb(cli); + if (!cli_receive_smb(cli)) { + return False; + } + + return !cli_is_error(cli); +} + + |