2007-12-01 03:13:35 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-04-25 18:04:06 +04:00
client RAP calls
2005-02-23 20:29:28 +03:00
Copyright ( C ) Andrew Tridgell 1994 - 1998
Copyright ( C ) Gerald ( Jerry ) Carter 2004
2007-12-10 01:18:54 +03:00
Copyright ( C ) James Peach 2007
2007-12-01 03:13:35 +03:00
2000-04-25 18:04:06 +04:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2000-04-25 18:04:06 +04:00
( at your option ) any later version .
2007-12-01 03:13:35 +03:00
2000-04-25 18:04:06 +04:00
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 .
2007-12-01 03:13:35 +03:00
2000-04-25 18:04:06 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2000-04-25 18:04:06 +04:00
*/
# include "includes.h"
2009-03-17 12:08:31 +03:00
# include "../libcli/auth/libcli_auth.h"
2010-04-26 17:42:47 +04:00
# include "../librpc/gen_ndr/rap.h"
2011-04-28 19:38:09 +04:00
# include "../lib/util/tevent_ntstatus.h"
2010-08-26 11:58:09 +04:00
# include "async_smb.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2011-02-24 12:46:55 +03:00
# include "libsmb/clirap.h"
2011-02-25 02:03:01 +03:00
# include "trans2.h"
2012-05-26 13:45:09 +04:00
# include "../libcli/smb/smbXcli_base.h"
2023-08-23 16:07:29 +03:00
# include "libcli/smb/reparse.h"
2017-07-21 22:41:11 +03:00
# include "cli_smb2_fnum.h"
2020-08-07 21:17:34 +03:00
# include "lib/util/string_wrappers.h"
2000-04-25 18:04:06 +04:00
2019-01-15 20:14:17 +03:00
# include <gnutls/gnutls.h>
# include <gnutls/crypto.h>
2011-02-09 22:56:57 +03:00
# define PIPE_LANMAN "\\PIPE\\LANMAN"
2000-04-25 18:04:06 +04:00
/****************************************************************************
2007-03-17 03:15:18 +03:00
Call a remote api
2000-04-25 18:04:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-03-17 03:15:18 +03:00
2007-10-19 04:40:25 +04:00
bool cli_api ( struct cli_state * cli ,
2000-04-25 18:04:06 +04:00
char * param , int prcnt , int mprcnt ,
char * data , int drcnt , int mdrcnt ,
2003-03-13 03:51:05 +03:00
char * * rparam , unsigned int * rprcnt ,
char * * rdata , unsigned int * rdrcnt )
2000-04-25 18:04:06 +04:00
{
2011-01-16 15:07:35 +03:00
NTSTATUS status ;
uint8_t * my_rparam , * my_rdata ;
uint32_t num_my_rparam , num_my_rdata ;
status = cli_trans ( talloc_tos ( ) , cli , SMBtrans ,
PIPE_LANMAN , 0 , /* name, fid */
0 , 0 , /* function, flags */
NULL , 0 , 0 , /* setup */
( uint8_t * ) param , prcnt , mprcnt , /* Params, length, max */
( uint8_t * ) data , drcnt , mdrcnt , /* Data, length, max */
NULL , /* recv_flags2 */
NULL , 0 , NULL , /* rsetup */
& my_rparam , 0 , & num_my_rparam ,
& my_rdata , 0 , & num_my_rdata ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return false ;
}
/*
* I know this memcpy massively hurts , but there are just tons
* of callers of cli_api that eventually need changing to
* talloc
*/
2014-04-14 16:37:29 +04:00
* rparam = ( char * ) smb_memdup ( my_rparam , num_my_rparam ) ;
2011-01-16 15:07:35 +03:00
if ( * rparam = = NULL ) {
goto fail ;
}
* rprcnt = num_my_rparam ;
TALLOC_FREE ( my_rparam ) ;
2014-04-14 16:37:29 +04:00
* rdata = ( char * ) smb_memdup ( my_rdata , num_my_rdata ) ;
2011-01-16 15:07:35 +03:00
if ( * rdata = = NULL ) {
goto fail ;
}
* rdrcnt = num_my_rdata ;
TALLOC_FREE ( my_rdata ) ;
return true ;
fail :
TALLOC_FREE ( my_rdata ) ;
TALLOC_FREE ( my_rparam ) ;
* rparam = NULL ;
* rprcnt = 0 ;
* rdata = NULL ;
* rdrcnt = 0 ;
return false ;
2000-04-25 18:04:06 +04:00
}
/****************************************************************************
2007-03-17 03:15:18 +03:00
Call a NetShareEnum - try and browse available connections on a host .
2000-04-25 18:04:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-03-17 03:15:18 +03:00
2024-08-18 21:48:48 +03:00
NTSTATUS cli_RNetShareEnum (
struct cli_state * cli ,
void ( * fn ) ( const char * , uint32_t , const char * , void * ) ,
void * state )
2000-04-25 18:04:06 +04:00
{
2024-08-18 21:36:45 +03:00
uint8_t * rparam = NULL ;
uint8_t * rdata = NULL ;
2024-08-18 21:19:56 +03:00
char * rdata_end = NULL ;
2024-08-18 21:36:45 +03:00
char * p = NULL ;
2003-08-15 05:42:30 +04:00
unsigned int rdrcnt , rprcnt ;
2007-12-01 03:13:35 +03:00
char param [ 1024 ] ;
2000-04-30 19:13:15 +04:00
int count = - 1 ;
2024-08-18 21:19:56 +03:00
int i , converter ;
2020-05-02 15:54:01 +03:00
int res ;
2024-08-18 21:36:45 +03:00
NTSTATUS status ;
2000-04-25 18:04:06 +04:00
2000-04-30 19:13:15 +04:00
/* now send a SMBtrans command with api RNetShareEnum */
p = param ;
SSVAL ( p , 0 , 0 ) ; /* api number */
p + = 2 ;
2007-12-01 03:13:35 +03:00
strlcpy ( p , " WrLeh " , sizeof ( param ) - PTR_DIFF ( p , param ) ) ;
2007-04-03 00:10:21 +04:00
p = skip_string ( param , sizeof ( param ) , p ) ;
2007-12-01 03:13:35 +03:00
strlcpy ( p , " B13BWz " , sizeof ( param ) - PTR_DIFF ( p , param ) ) ;
2007-04-03 00:10:21 +04:00
p = skip_string ( param , sizeof ( param ) , p ) ;
2000-04-30 19:13:15 +04:00
SSVAL ( p , 0 , 1 ) ;
/*
* Win2k needs a * smaller * buffer than 0xFFFF here -
* it returns " out of server memory " with 0xFFFF ! ! ! JRA .
*/
SSVAL ( p , 2 , 0xFFE0 ) ;
p + = 4 ;
2007-12-01 03:13:35 +03:00
2024-08-18 21:36:45 +03:00
status = cli_trans ( talloc_tos ( ) , /* mem_ctx */
cli , /* cli */
SMBtrans , /* cmd */
PIPE_LANMAN , /* name */
0 , /* fid */
0 , /* function */
0 , /* flags */
NULL , /* setup */
0 , /* num_setup */
0 , /* max_setup */
( uint8_t * ) param , /* param */
PTR_DIFF ( p , param ) , /* num_param */
1024 , /* max_param */
NULL , /* data */
0 , /* num_data */
0xFFE0 , /* max_data, for W2K */
NULL , /* recv_flags2 */
NULL , /* rsetup */
0 , /* min_rsetup */
NULL , /* num_rsetup */
& rparam , /* rparam */
6 , /* min_rparam */
& rprcnt , /* num_rparam */
& rdata , /* rdata */
0 , /* min_rdata */
& rdrcnt ) ; /* num_rdata */
if ( ! NT_STATUS_IS_OK ( status ) ) {
2020-05-02 15:54:01 +03:00
DEBUG ( 4 , ( " NetShareEnum failed \n " ) ) ;
goto done ;
}
2024-08-18 21:36:45 +03:00
res = PULL_LE_U16 ( rparam , 0 ) ;
2020-05-02 15:54:01 +03:00
2024-08-18 21:19:56 +03:00
if ( ! ( res = = 0 | | res = = ERRmoredata ) ) {
DEBUG ( 4 , ( " NetShareEnum res=%d \n " , res ) ) ;
2024-08-18 21:48:48 +03:00
status = werror_to_ntstatus ( W_ERROR ( res ) ) ;
2024-08-18 21:19:56 +03:00
goto done ;
}
converter = SVAL ( rparam , 2 ) ;
2024-08-18 21:36:45 +03:00
rdata_end = ( char * ) rdata + rdrcnt ;
2024-08-18 21:19:56 +03:00
count = SVAL ( rparam , 4 ) ;
2024-08-18 21:36:45 +03:00
p = ( char * ) rdata ;
2020-05-02 15:54:01 +03:00
2024-08-18 21:19:56 +03:00
for ( i = 0 ; i < count ; i + + , p + = 20 ) {
char * sname ;
int type ;
int comment_offset ;
const char * cmnt ;
const char * p1 ;
char * s1 , * s2 ;
size_t len ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
if ( p + 20 > rdata_end ) {
2020-05-02 15:54:01 +03:00
TALLOC_FREE ( frame ) ;
2024-08-18 21:19:56 +03:00
break ;
2000-04-30 19:13:15 +04:00
}
2024-08-18 21:19:56 +03:00
sname = p ;
type = SVAL ( p , 14 ) ;
comment_offset = ( IVAL ( p , 16 ) & 0xFFFF ) - converter ;
if ( comment_offset < 0 | |
comment_offset > ( int ) rdrcnt ) {
TALLOC_FREE ( frame ) ;
break ;
}
2024-08-18 21:36:45 +03:00
cmnt = comment_offset ? ( ( char * ) rdata + comment_offset ) : " " ;
2024-08-18 21:19:56 +03:00
/* Work out the comment length. */
for ( p1 = cmnt , len = 0 ; * p1 & &
p1 < rdata_end ; len + + )
p1 + + ;
if ( ! * p1 ) {
len + + ;
}
pull_string_talloc ( frame , rdata , 0 ,
& s1 , sname , 14 , STR_ASCII ) ;
pull_string_talloc ( frame , rdata , 0 ,
& s2 , cmnt , len , STR_ASCII ) ;
if ( ! s1 | | ! s2 ) {
TALLOC_FREE ( frame ) ;
continue ;
}
fn ( s1 , type , s2 , state ) ;
TALLOC_FREE ( frame ) ;
2020-05-02 15:54:01 +03:00
}
2007-12-01 03:13:35 +03:00
2020-05-02 15:54:01 +03:00
done :
2024-08-18 21:36:45 +03:00
TALLOC_FREE ( rparam ) ;
TALLOC_FREE ( rdata ) ;
2007-12-01 03:13:35 +03:00
2024-08-18 21:48:48 +03:00
return status ;
2000-04-25 18:04:06 +04:00
}
/****************************************************************************
2007-03-17 03:15:18 +03:00
Call a NetServerEnum for the specified workgroup and servertype mask . This
function then calls the specified callback function for each name returned .
2000-04-25 18:04:06 +04:00
2007-03-17 03:15:18 +03:00
The callback function takes 4 arguments : the machine name , the server type ,
the comment and a state pointer .
2000-04-25 18:04:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-03-17 03:15:18 +03:00
2015-05-10 02:59:45 +03:00
bool cli_NetServerEnum ( struct cli_state * cli , char * workgroup , uint32_t stype ,
void ( * fn ) ( const char * , uint32_t , const char * , void * ) ,
2004-02-26 17:34:44 +03:00
void * state )
2000-04-25 18:04:06 +04:00
{
2024-08-18 22:30:24 +03:00
uint8_t * rparam = NULL ;
uint8_t * rdata = NULL ;
2007-12-10 01:18:54 +03:00
char * rdata_end = NULL ;
2024-08-18 22:30:24 +03:00
uint32_t rdrcnt , rprcnt ;
2000-04-25 18:04:06 +04:00
char * p ;
2007-12-01 03:13:35 +03:00
char param [ 1024 ] ;
2000-04-25 18:04:06 +04:00
int uLevel = 1 ;
2007-11-20 04:43:28 +03:00
size_t len ;
2015-05-10 02:59:45 +03:00
uint32_t func = RAP_NetServerEnum2 ;
2007-12-10 01:18:54 +03:00
char * last_entry = NULL ;
int total_cnt = 0 ;
int return_cnt = 0 ;
int res ;
2024-08-18 22:30:24 +03:00
NTSTATUS status ;
2001-01-04 14:35:55 +03:00
2004-05-09 00:15:52 +04:00
errno = 0 ; /* reset */
2007-12-10 01:18:54 +03:00
/*
* This may take more than one transaction , so we should loop until
* we no longer get a more data to process or we have all of the
* items .
*/
do {
/* send a SMBtrans command with api NetServerEnum */
p = param ;
SIVAL ( p , 0 , func ) ; /* api number */
p + = 2 ;
2010-02-08 20:38:03 +03:00
if ( func = = RAP_NetServerEnum3 ) {
strlcpy ( p , " WrLehDzz " , sizeof ( param ) - PTR_DIFF ( p , param ) ) ;
2007-12-10 01:18:54 +03:00
} else {
strlcpy ( p , " WrLehDz " , sizeof ( param ) - PTR_DIFF ( p , param ) ) ;
}
2007-12-01 03:13:35 +03:00
2007-12-10 01:18:54 +03:00
p = skip_string ( param , sizeof ( param ) , p ) ;
strlcpy ( p , " B16BBDz " , sizeof ( param ) - PTR_DIFF ( p , param ) ) ;
p = skip_string ( param , sizeof ( param ) , p ) ;
SSVAL ( p , 0 , uLevel ) ;
SSVAL ( p , 2 , CLI_BUFFER_SIZE ) ;
p + = 4 ;
SIVAL ( p , 0 , stype ) ;
p + = 4 ;
/* If we have more data, tell the server where
* to continue from .
*/
len = push_ascii ( p ,
2010-02-08 20:38:03 +03:00
workgroup ,
2007-12-10 01:18:54 +03:00
sizeof ( param ) - PTR_DIFF ( p , param ) - 1 ,
STR_TERMINATE | STR_UPPER ) ;
2014-06-08 08:51:44 +04:00
if ( len = = 0 ) {
2008-01-10 00:25:52 +03:00
SAFE_FREE ( last_entry ) ;
2007-12-10 01:18:54 +03:00
return false ;
}
p + = len ;
2001-01-04 14:35:55 +03:00
2010-02-08 20:38:03 +03:00
if ( func = = RAP_NetServerEnum3 ) {
len = push_ascii ( p ,
last_entry ? last_entry : " " ,
sizeof ( param ) - PTR_DIFF ( p , param ) - 1 ,
STR_TERMINATE ) ;
2014-06-08 08:51:44 +04:00
if ( len = = 0 ) {
2010-02-08 20:38:03 +03:00
SAFE_FREE ( last_entry ) ;
return false ;
}
p + = len ;
}
/* Next time through we need to use the continue api */
func = RAP_NetServerEnum3 ;
2024-08-18 22:30:24 +03:00
status = cli_trans ( talloc_tos ( ) , /* mem_ctx */
cli , /* cli */
SMBtrans , /* cmd */
PIPE_LANMAN , /* name */
0 , /* fid */
0 , /* function */
0 , /* flags */
NULL , /* setup */
0 , /* num_setup */
0 , /* max_setup */
( uint8_t * ) param , /* param */
PTR_DIFF ( p , param ) , /* num_param */
8 , /* max_param */
NULL , /* data */
0 , /* num_data */
CLI_BUFFER_SIZE , /* max_data */
NULL , /* recv_flags2 */
NULL , /* rsetup */
0 , /* min_rsetup */
NULL , /* num_rsetup */
& rparam , /* rparam */
6 , /* min_rparam */
& rprcnt , /* num_rparam */
& rdata , /* rdata */
0 , /* min_rdata */
& rdrcnt ) ; /* num_rdata */
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-12-10 01:18:54 +03:00
/* break out of the loop on error */
res = - 1 ;
break ;
}
2007-12-01 03:13:35 +03:00
2024-08-18 22:30:24 +03:00
rdata_end = ( char * ) rdata + rdrcnt ;
2020-05-02 16:10:14 +03:00
2024-08-18 22:30:24 +03:00
res = PULL_LE_U16 ( rparam , 0 ) ;
2007-12-01 03:13:35 +03:00
r19231: I encountered a WinXP/Home system which, acting as the master browser for its
workgroup, decided periodically to stop sending recognized responses to a
NetServerEnum2 request for the workgroup. Instead of returning the list of
servers (only itself; nothing else in the workgroup), it returns a status code
of 8 which is unsupported by samba3, samba4, and ethereal.
The code for this request assumed that if an unexpected status code was
received, the connection had a problem, i.e. that cli_errno() would show a
problem. That turns out not to be the case.
This patch changes the behavior so tha any time a response is received and
cli_errno() == 0, we continue processing the reply and base our response on
the returned count (zero). The pre-existing code then converts this count=0
into an ENOENT errno which can be properly handled by the application (whereas
an error return with errno=0 can't be).
This packet dump has only 2 frames. Sorry about the text version but it's
most easily attached to this log message. I also have it saved as .pcap if
anyone wants it.
Derrell
No. Time Source Destination Protocol Info
1 14:31:59.802668 192.168.1.106 192.168.1.100 LANMAN NetServerEnum2 Request, Server, SQL Server, Domain Controller, Backup Controller, Time Source, Apple Server, Novell Server, Domain Member Server, Print Queue Server, Dialin Server, Xenix Server, NT Workstation, Windows for Workgroups, Unknown server type:14, NT Server
Frame 1 (196 bytes on wire, 196 bytes captured)
Arrival Time: Oct 10, 2006 14:31:59.802668000
Time delta from previous packet: 0.000000000 seconds
Time since reference or first frame: 0.000000000 seconds
Frame Number: 1
Packet Length: 196 bytes
Capture Length: 196 bytes
Protocols in frame: eth:ip:tcp:nbss:smb
Ethernet II, Src: IntelCor_4a:47:bb (00:13:20:4a:47:bb), Dst: Micro-St_74:16:e7 (00:0c:76:74:16:e7)
Destination: Micro-St_74:16:e7 (00:0c:76:74:16:e7)
Source: IntelCor_4a:47:bb (00:13:20:4a:47:bb)
Type: IP (0x0800)
Internet Protocol, Src: 192.168.1.106 (192.168.1.106), Dst: 192.168.1.100 (192.168.1.100)
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
0000 00.. = Differentiated Services Codepoint: Default (0x00)
.... ..0. = ECN-Capable Transport (ECT): 0
.... ...0 = ECN-CE: 0
Total Length: 182
Identification: 0xb838 (47160)
Flags: 0x04 (Don't Fragment)
0... = Reserved bit: Not set
.1.. = Don't fragment: Set
..0. = More fragments: Not set
Fragment offset: 0
Time to live: 64
Protocol: TCP (0x06)
Header checksum: 0xfdea [correct]
Good: True
Bad : False
Source: 192.168.1.106 (192.168.1.106)
Destination: 192.168.1.100 (192.168.1.100)
Transmission Control Protocol, Src Port: 44932 (44932), Dst Port: netbios-ssn (139), Seq: 851982066, Ack: 1274726157, Len: 130
Source port: 44932 (44932)
Destination port: netbios-ssn (139)
Sequence number: 851982066
Next sequence number: 851982196
Acknowledgement number: 1274726157
Header length: 32 bytes
Flags: 0x0018 (PSH, ACK)
0... .... = Congestion Window Reduced (CWR): Not set
.0.. .... = ECN-Echo: Not set
..0. .... = Urgent: Not set
...1 .... = Acknowledgment: Set
.... 1... = Push: Set
.... .0.. = Reset: Not set
.... ..0. = Syn: Not set
.... ...0 = Fin: Not set
Window size: 6432
Checksum: 0xb4e0 [correct]
Options: (12 bytes)
NOP
NOP
Time stamp: tsval 1184074739, tsecr 11576161
NetBIOS Session Service
Message Type: Session message
Flags: 0x00
.... ...0 = Add 0 to length
Length: 126
SMB (Server Message Block Protocol)
SMB Header
Server Component: SMB
Response in: 2
SMB Command: Trans (0x25)
NT Status: STATUS_SUCCESS (0x00000000)
Flags: 0x08
0... .... = Request/Response: Message is a request to the server
.0.. .... = Notify: Notify client only on open
..0. .... = Oplocks: OpLock not requested/granted
...0 .... = Canonicalized Pathnames: Pathnames are not canonicalized
.... 1... = Case Sensitivity: Path names are caseless
.... ..0. = Receive Buffer Posted: Receive buffer has not been posted
.... ...0 = Lock and Read: Lock&Read, Write&Unlock are not supported
Flags2: 0xc801
1... .... .... .... = Unicode Strings: Strings are Unicode
.1.. .... .... .... = Error Code Type: Error codes are NT error codes
..0. .... .... .... = Execute-only Reads: Don't permit reads if execute-only
...0 .... .... .... = Dfs: Don't resolve pathnames with Dfs
.... 1... .... .... = Extended Security Negotiation: Extended security negotiation is supported
.... .... .0.. .... = Long Names Used: Path names in request are not long file names
.... .... .... .0.. = Security Signatures: Security signatures are not supported
.... .... .... ..0. = Extended Attributes: Extended attributes are not supported
.... .... .... ...1 = Long Names Allowed: Long file names are allowed in the response
Process ID High: 0
Signature: 0000000000000000
Reserved: 0000
Tree ID: 2048
Process ID: 12967
User ID: 2048
Multiplex ID: 6
Trans Request (0x25)
Word Count (WCT): 14
Total Parameter Count: 36
Total Data Count: 0
Max Parameter Count: 8
Max Data Count: 65535
Max Setup Count: 0
Reserved: 00
Flags: 0x0000
.... .... .... ..0. = One Way Transaction: Two way transaction
.... .... .... ...0 = Disconnect TID: Do NOT disconnect TID
Timeout: Return immediately (0)
Reserved: 0000
Parameter Count: 36
Parameter Offset: 90
Data Count: 0
Data Offset: 126
Setup Count: 0
Reserved: 00
Byte Count (BCC): 63
Transaction Name: \PIPE\LANMAN
SMB Pipe Protocol
Microsoft Windows Lanman Remote API Protocol
Function Code: NetServerEnum2 (104)
Parameter Descriptor: WrLehDz
Return Descriptor: B16BBDz
Detail Level: 1
Receive Buffer Length: 65535
Server Type: 0x0000fffe
.... .... .... .... .... .... .... ...0 = Workstation: This is NOT a Workstation
.... .... .... .... .... .... .... ..1. = Server: This is a Server
.... .... .... .... .... .... .... .1.. = SQL: This is an SQL server
.... .... .... .... .... .... .... 1... = Domain Controller: This is a Domain Controller
.... .... .... .... .... .... ...1 .... = Backup Controller: This is a Backup Controller
.... .... .... .... .... .... ..1. .... = Time Source: This is a Time Source
.... .... .... .... .... .... .1.. .... = Apple: This is an Apple host
.... .... .... .... .... .... 1... .... = Novell: This is a Novell server
.... .... .... .... .... ...1 .... .... = Member: This is a Domain Member server
.... .... .... .... .... ..1. .... .... = Print: This is a Print Queue server
.... .... .... .... .... .1.. .... .... = Dialin: This is a Dialin server
.... .... .... .... .... 1... .... .... = Xenix: This is a Xenix server
.... .... .... .... ...1 .... .... .... = NT Workstation: This is an NT Workstation
.... .... .... .... ..1. .... .... .... = WfW: This is a WfW host
.... .... .... .... 1... .... .... .... = NT Server: This is an NT Server
.... .... .... ...0 .... .... .... .... = Potential Browser: This is NOT a Potential Browser
.... .... .... ..0. .... .... .... .... = Backup Browser: This is NOT a Backup Browser
.... .... .... .0.. .... .... .... .... = Master Browser: This is NOT a Master Browser
.... .... .... 0... .... .... .... .... = Domain Master Browser: This is NOT a Domain Master Browser
.... .... ...0 .... .... .... .... .... = OSF: This is NOT an OSF host
.... .... ..0. .... .... .... .... .... = VMS: This is NOT a VMS host
.... .... .0.. .... .... .... .... .... = Windows 95+: This is NOT a Windows 95 or above host
.0.. .... .... .... .... .... .... .... = Local: This is NOT a local list only request
0... .... .... .... .... .... .... .... = Domain Enum: This is NOT a Domain Enum request
Enumeration Domain: WORKGROUP
No. Time Source Destination Protocol Info
2 14:31:59.803918 192.168.1.100 192.168.1.106 LANMAN NetServerEnum2 Response
Frame 2 (134 bytes on wire, 134 bytes captured)
Arrival Time: Oct 10, 2006 14:31:59.803918000
Time delta from previous packet: 0.001250000 seconds
Time since reference or first frame: 0.001250000 seconds
Frame Number: 2
Packet Length: 134 bytes
Capture Length: 134 bytes
Protocols in frame: eth:ip:tcp:nbss:smb
Ethernet II, Src: Micro-St_74:16:e7 (00:0c:76:74:16:e7), Dst: IntelCor_4a:47:bb (00:13:20:4a:47:bb)
Destination: IntelCor_4a:47:bb (00:13:20:4a:47:bb)
Source: Micro-St_74:16:e7 (00:0c:76:74:16:e7)
Type: IP (0x0800)
Internet Protocol, Src: 192.168.1.100 (192.168.1.100), Dst: 192.168.1.106 (192.168.1.106)
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
0000 00.. = Differentiated Services Codepoint: Default (0x00)
.... ..0. = ECN-Capable Transport (ECT): 0
.... ...0 = ECN-CE: 0
Total Length: 120
Identification: 0xea10 (59920)
Flags: 0x04 (Don't Fragment)
0... = Reserved bit: Not set
.1.. = Don't fragment: Set
..0. = More fragments: Not set
Fragment offset: 0
Time to live: 128
Protocol: TCP (0x06)
Header checksum: 0x8c50 [correct]
Good: True
Bad : False
Source: 192.168.1.100 (192.168.1.100)
Destination: 192.168.1.106 (192.168.1.106)
Transmission Control Protocol, Src Port: netbios-ssn (139), Dst Port: 44932 (44932), Seq: 1274726157, Ack: 851982196, Len: 68
Source port: netbios-ssn (139)
Destination port: 44932 (44932)
Sequence number: 1274726157
Next sequence number: 1274726225
Acknowledgement number: 851982196
Header length: 32 bytes
Flags: 0x0018 (PSH, ACK)
0... .... = Congestion Window Reduced (CWR): Not set
.0.. .... = ECN-Echo: Not set
..0. .... = Urgent: Not set
...1 .... = Acknowledgment: Set
.... 1... = Push: Set
.... .0.. = Reset: Not set
.... ..0. = Syn: Not set
.... ...0 = Fin: Not set
Window size: 64606
Checksum: 0x1e0d [correct]
Options: (12 bytes)
NOP
NOP
Time stamp: tsval 11576161, tsecr 1184074739
NetBIOS Session Service
Message Type: Session message
Flags: 0x00
.... ...0 = Add 0 to length
Length: 64
SMB (Server Message Block Protocol)
SMB Header
Server Component: SMB
Response to: 1
Time from request: 0.001250000 seconds
SMB Command: Trans (0x25)
NT Status: STATUS_SUCCESS (0x00000000)
Flags: 0x88
1... .... = Request/Response: Message is a response to the client/redirector
.0.. .... = Notify: Notify client only on open
..0. .... = Oplocks: OpLock not requested/granted
...0 .... = Canonicalized Pathnames: Pathnames are not canonicalized
.... 1... = Case Sensitivity: Path names are caseless
.... ..0. = Receive Buffer Posted: Receive buffer has not been posted
.... ...0 = Lock and Read: Lock&Read, Write&Unlock are not supported
Flags2: 0xc801
1... .... .... .... = Unicode Strings: Strings are Unicode
.1.. .... .... .... = Error Code Type: Error codes are NT error codes
..0. .... .... .... = Execute-only Reads: Don't permit reads if execute-only
...0 .... .... .... = Dfs: Don't resolve pathnames with Dfs
.... 1... .... .... = Extended Security Negotiation: Extended security negotiation is supported
.... .... .0.. .... = Long Names Used: Path names in request are not long file names
.... .... .... .0.. = Security Signatures: Security signatures are not supported
.... .... .... ..0. = Extended Attributes: Extended attributes are not supported
.... .... .... ...1 = Long Names Allowed: Long file names are allowed in the response
Process ID High: 0
Signature: 0000000000000000
Reserved: 0000
Tree ID: 2048
Process ID: 12967
User ID: 2048
Multiplex ID: 6
Trans Response (0x25)
Word Count (WCT): 10
Total Parameter Count: 8
Total Data Count: 0
Reserved: 0000
Parameter Count: 8
Parameter Offset: 56
Parameter Displacement: 0
Data Count: 0
Data Offset: 64
Data Displacement: 0
Setup Count: 0
Reserved: 00
Byte Count (BCC): 9
Padding: 00
SMB Pipe Protocol
Microsoft Windows Lanman Remote API Protocol
Function Code: NetServerEnum2 (104)
Status: Unknown (8)
Convert: 0
Entry Count: 0
Available Entries: 0
(This used to be commit 88fa5ac7347cbae92abe17da8d3af00e85110c43)
2006-10-11 04:33:48 +04:00
if ( res = = 0 | | res = = ERRmoredata | |
( res ! = - 1 & & cli_errno ( cli ) = = 0 ) ) {
2007-12-10 01:18:54 +03:00
char * sname = NULL ;
int i , count ;
2000-04-30 19:13:15 +04:00
int converter = SVAL ( rparam , 2 ) ;
2007-12-10 01:18:54 +03:00
/* Get the number of items returned in this buffer */
count = SVAL ( rparam , 4 ) ;
/* The next field contains the number of items left,
* including those returned in this buffer . So the
* first time through this should contain all of the
* entries .
*/
if ( total_cnt = = 0 ) {
total_cnt = SVAL ( rparam , 6 ) ;
}
/* Keep track of how many we have read */
return_cnt + = count ;
2024-08-18 22:30:24 +03:00
p = ( char * ) rdata ;
2007-12-01 03:13:35 +03:00
2007-12-10 01:18:54 +03:00
/* The last name in the previous NetServerEnum reply is
* sent back to server in the NetServerEnum3 request
* ( last_entry ) . The next reply should repeat this entry
* as the first element . We have no proof that this is
* always true , but from traces that seems to be the
* behavior from Window Servers . So first lets do a lot
* of checking , just being paranoid . If the string
* matches then we already saw this entry so skip it .
*
* NOTE : sv1_name field must be null terminated and has
* a max size of 16 ( NetBIOS Name ) .
*/
if ( last_entry & & count & & p & &
( strncmp ( last_entry , p , 16 ) = = 0 ) ) {
count - = 1 ; /* Skip this entry */
return_cnt = - 1 ; /* Not part of total, so don't count. */
2024-08-18 22:30:24 +03:00
p = ( char * ) rdata + 26 ; /* Skip the whole record */
2007-12-10 01:18:54 +03:00
}
for ( i = 0 ; i < count ; i + + , p + = 26 ) {
2007-12-01 03:13:35 +03:00
int comment_offset ;
const char * cmnt ;
const char * p1 ;
char * s1 , * s2 ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2010-02-04 16:03:20 +03:00
uint32_t entry_stype ;
2007-12-01 03:13:35 +03:00
if ( p + 26 > rdata_end ) {
TALLOC_FREE ( frame ) ;
break ;
}
sname = p ;
comment_offset = ( IVAL ( p , 22 ) & 0xFFFF ) - converter ;
2024-08-18 22:30:24 +03:00
cmnt = comment_offset ? ( ( char * ) rdata +
comment_offset )
: " " ;
2001-06-21 05:01:15 +04:00
2010-02-09 23:17:08 +03:00
if ( comment_offset < 0 | | comment_offset > = ( int ) rdrcnt ) {
2007-12-01 03:13:35 +03:00
TALLOC_FREE ( frame ) ;
continue ;
}
/* Work out the comment length. */
for ( p1 = cmnt , len = 0 ; * p1 & &
p1 < rdata_end ; len + + )
p1 + + ;
if ( ! * p1 ) {
len + + ;
}
2001-01-04 14:35:55 +03:00
2010-02-04 16:03:20 +03:00
entry_stype = IVAL ( p , 18 ) & ~ SV_TYPE_LOCAL_LIST_ONLY ;
2001-01-04 14:35:55 +03:00
2007-12-01 03:13:35 +03:00
pull_string_talloc ( frame , rdata , 0 ,
& s1 , sname , 16 , STR_ASCII ) ;
pull_string_talloc ( frame , rdata , 0 ,
& s2 , cmnt , len , STR_ASCII ) ;
if ( ! s1 | | ! s2 ) {
TALLOC_FREE ( frame ) ;
continue ;
}
2010-02-04 16:03:20 +03:00
fn ( s1 , entry_stype , s2 , state ) ;
2007-12-01 03:13:35 +03:00
TALLOC_FREE ( frame ) ;
2000-04-25 18:04:06 +04:00
}
2007-12-10 01:18:54 +03:00
/* We are done with the old last entry, so now we can free it */
if ( last_entry ) {
SAFE_FREE ( last_entry ) ; /* This will set it to null */
}
/* We always make a copy of the last entry if we have one */
if ( sname ) {
last_entry = smb_xstrdup ( sname ) ;
}
/* If we have more data, but no last entry then error out */
if ( ! last_entry & & ( res = = ERRmoredata ) ) {
errno = EINVAL ;
res = 0 ;
}
2000-04-25 18:04:06 +04:00
}
2007-12-10 01:18:54 +03:00
2024-08-18 22:30:24 +03:00
TALLOC_FREE ( rparam ) ;
TALLOC_FREE ( rdata ) ;
2007-12-10 01:18:54 +03:00
} while ( ( res = = ERRmoredata ) & & ( total_cnt > return_cnt ) ) ;
2007-12-01 03:13:35 +03:00
2024-08-18 22:30:24 +03:00
TALLOC_FREE ( rparam ) ;
TALLOC_FREE ( rdata ) ;
2007-12-10 01:18:54 +03:00
SAFE_FREE ( last_entry ) ;
2004-05-09 00:15:52 +04:00
2007-12-10 01:18:54 +03:00
if ( res = = - 1 ) {
errno = cli_errno ( cli ) ;
2004-05-09 00:15:52 +04:00
} else {
2007-12-10 01:18:54 +03:00
if ( ! return_cnt ) {
/* this is a very special case, when the domain master for the
work group isn ' t part of the work group itself , there is something
wild going on */
errno = ENOENT ;
}
2004-05-09 00:15:52 +04:00
}
2007-12-01 03:13:35 +03:00
2007-12-10 01:18:54 +03:00
return ( return_cnt > 0 ) ;
2000-04-25 18:04:06 +04:00
}
/****************************************************************************
2007-03-17 03:15:18 +03:00
Send a SamOEMChangePassword command .
2000-04-25 18:04:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-03-17 03:15:18 +03:00
2024-08-18 13:55:34 +03:00
NTSTATUS cli_oem_change_password ( struct cli_state * cli ,
const char * user ,
const char * new_password ,
const char * old_password )
2000-04-25 18:04:06 +04:00
{
2007-12-01 03:13:35 +03:00
char param [ 1024 ] ;
2024-08-18 10:37:13 +03:00
uint8_t data [ 532 ] ;
2007-03-17 03:15:18 +03:00
char * p = param ;
unsigned char old_pw_hash [ 16 ] ;
unsigned char new_pw_hash [ 16 ] ;
unsigned int param_len = 0 ;
2024-08-18 10:37:13 +03:00
uint8_t * rparam = NULL ;
2024-08-18 13:37:13 +03:00
uint32_t rprcnt ;
2019-01-15 20:14:17 +03:00
gnutls_cipher_hd_t cipher_hnd = NULL ;
gnutls_datum_t old_pw_key = {
. data = old_pw_hash ,
. size = sizeof ( old_pw_hash ) ,
} ;
int rc ;
2024-08-18 10:37:13 +03:00
NTSTATUS status ;
2007-03-17 03:15:18 +03:00
if ( strlen ( user ) > = sizeof ( fstring ) - 1 ) {
2024-08-05 18:11:43 +03:00
DBG_ERR ( " user name %s is too long. \n " , user ) ;
2024-08-18 13:55:34 +03:00
return NT_STATUS_NAME_TOO_LONG ;
2007-03-17 03:15:18 +03:00
}
SSVAL ( p , 0 , 214 ) ; /* SamOEMChangePassword command. */
p + = 2 ;
2007-12-01 03:13:35 +03:00
strlcpy ( p , " zsT " , sizeof ( param ) - PTR_DIFF ( p , param ) ) ;
2007-04-03 00:10:21 +04:00
p = skip_string ( param , sizeof ( param ) , p ) ;
2007-12-01 03:13:35 +03:00
strlcpy ( p , " B516B16 " , sizeof ( param ) - PTR_DIFF ( p , param ) ) ;
2007-04-03 00:10:21 +04:00
p = skip_string ( param , sizeof ( param ) , p ) ;
2007-12-01 03:13:35 +03:00
strlcpy ( p , user , sizeof ( param ) - PTR_DIFF ( p , param ) ) ;
2007-04-03 00:10:21 +04:00
p = skip_string ( param , sizeof ( param ) , p ) ;
2007-03-17 03:15:18 +03:00
SSVAL ( p , 0 , 532 ) ;
p + = 2 ;
param_len = PTR_DIFF ( p , param ) ;
/*
* Get the Lanman hash of the old password , we
* use this as the key to make_oem_passwd_hash ( ) .
*/
E_deshash ( old_password , old_pw_hash ) ;
encode_pw_buffer ( data , new_password , STR_ASCII ) ;
2007-12-01 03:13:35 +03:00
2004-01-26 11:45:02 +03:00
# ifdef DEBUG_PASSWORD
2007-03-17 03:15:18 +03:00
DEBUG ( 100 , ( " make_oem_passwd_hash \n " ) ) ;
2007-03-28 17:34:59 +04:00
dump_data ( 100 , data , 516 ) ;
2004-01-26 11:45:02 +03:00
# endif
2019-01-15 20:14:17 +03:00
rc = gnutls_cipher_init ( & cipher_hnd ,
GNUTLS_CIPHER_ARCFOUR_128 ,
& old_pw_key ,
NULL ) ;
if ( rc < 0 ) {
DBG_ERR ( " gnutls_cipher_init failed: %s \n " ,
gnutls_strerror ( rc ) ) ;
2024-08-18 13:55:34 +03:00
status = gnutls_error_to_ntstatus (
rc , NT_STATUS_CRYPTO_SYSTEM_INVALID ) ;
return status ;
2019-01-15 20:14:17 +03:00
}
rc = gnutls_cipher_encrypt ( cipher_hnd ,
data ,
516 ) ;
gnutls_cipher_deinit ( cipher_hnd ) ;
if ( rc < 0 ) {
2024-08-18 13:55:34 +03:00
status = gnutls_error_to_ntstatus (
rc , NT_STATUS_CRYPTO_SYSTEM_INVALID ) ;
return status ;
2019-01-15 20:14:17 +03:00
}
2000-04-25 18:04:06 +04:00
2007-12-01 03:13:35 +03:00
/*
2007-03-17 03:15:18 +03:00
* Now place the old password hash in the data .
*/
E_deshash ( new_password , new_pw_hash ) ;
2000-04-25 18:04:06 +04:00
2019-11-20 17:28:39 +03:00
rc = E_old_pw_hash ( new_pw_hash , old_pw_hash , ( uchar * ) & data [ 516 ] ) ;
if ( rc ! = 0 ) {
DBG_ERR ( " E_old_pw_hash failed: %s \n " , gnutls_strerror ( rc ) ) ;
2024-08-18 13:55:34 +03:00
status = gnutls_error_to_ntstatus (
rc , NT_STATUS_CRYPTO_SYSTEM_INVALID ) ;
return status ;
2019-11-20 17:28:39 +03:00
}
2000-04-25 18:04:06 +04:00
2024-08-18 10:37:13 +03:00
status = cli_trans ( talloc_tos ( ) , /* mem_ctx */
cli , /* cli */
SMBtrans , /* cmd */
PIPE_LANMAN , /* name */
0 , /* fid */
0 , /* function */
0 , /* flags */
NULL , /* setup */
0 , /* num_setup */
0 , /* max_setup */
( uint8_t * ) param , /* param */
param_len , /* num_param */
4 , /* max_param */
data , /* data */
2024-08-18 12:22:13 +03:00
sizeof ( data ) , /* num_data */
2024-08-18 10:37:13 +03:00
0 , /* max_data */
NULL , /* recv_flags2 */
NULL , /* rsetup */
0 , /* min_rsetup */
NULL , /* num_rsetup */
& rparam , /* rparam */
2024-08-18 13:37:13 +03:00
2 , /* min_rparam */
2024-08-18 10:37:13 +03:00
& rprcnt , /* num_rparam */
2024-08-18 13:37:13 +03:00
NULL , /* rdata */
2024-08-18 10:37:13 +03:00
0 , /* min_rdata */
2024-08-18 13:37:13 +03:00
NULL ) ; /* num_rdata */
2024-08-18 10:37:13 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2024-08-18 13:55:34 +03:00
return status ;
2007-03-17 03:15:18 +03:00
}
2024-08-18 13:37:13 +03:00
cli - > rap_error = PULL_LE_U16 ( rparam , 0 ) ;
2000-04-25 18:04:06 +04:00
2024-08-18 13:55:34 +03:00
status = werror_to_ntstatus ( W_ERROR ( cli - > rap_error ) ) ;
2024-08-18 10:37:13 +03:00
TALLOC_FREE ( rparam ) ;
2000-04-25 18:04:06 +04:00
2024-08-18 13:55:34 +03:00
return status ;
2000-04-25 18:04:06 +04:00
}
2020-03-30 17:47:52 +03:00
static void prep_basic_information_buf (
uint8_t buf [ 40 ] ,
struct timespec create_time ,
struct timespec access_time ,
struct timespec write_time ,
struct timespec change_time ,
2020-06-04 06:48:23 +03:00
uint32_t attr )
2019-12-01 11:01:13 +03:00
{
2020-03-30 17:47:52 +03:00
char * p = ( char * ) buf ;
2019-12-01 11:01:13 +03:00
/*
* Add the create , last access , modification , and status change times
*/
2020-03-26 16:33:58 +03:00
put_long_date_full_timespec (
TIMESTAMP_SET_NT_OR_BETTER , p , & create_time ) ;
2019-12-01 11:01:13 +03:00
p + = 8 ;
2020-03-26 16:33:58 +03:00
put_long_date_full_timespec (
TIMESTAMP_SET_NT_OR_BETTER , p , & access_time ) ;
2019-12-01 11:01:13 +03:00
p + = 8 ;
2020-03-26 16:33:58 +03:00
put_long_date_full_timespec (
TIMESTAMP_SET_NT_OR_BETTER , p , & write_time ) ;
2019-12-01 11:01:13 +03:00
p + = 8 ;
2020-03-26 16:33:58 +03:00
put_long_date_full_timespec (
TIMESTAMP_SET_NT_OR_BETTER , p , & change_time ) ;
2019-12-01 11:01:13 +03:00
p + = 8 ;
2020-06-04 06:48:23 +03:00
if ( attr = = ( uint32_t ) - 1 | | attr = = FILE_ATTRIBUTE_NORMAL ) {
2019-12-01 11:01:13 +03:00
/* No change. */
2020-06-03 21:01:36 +03:00
attr = 0 ;
} else if ( attr = = 0 ) {
2019-12-01 11:01:13 +03:00
/* Clear all existing attributes. */
2020-06-03 21:01:36 +03:00
attr = FILE_ATTRIBUTE_NORMAL ;
2019-12-01 11:01:13 +03:00
}
/* Add attributes */
2020-06-03 21:01:36 +03:00
SIVAL ( p , 0 , attr ) ;
2019-12-01 11:01:13 +03:00
p + = 4 ;
/* Add padding */
SIVAL ( p , 0 , 0 ) ;
p + = 4 ;
2020-03-30 17:47:52 +03:00
SMB_ASSERT ( PTR_DIFF ( p , buf ) = = 40 ) ;
}
NTSTATUS cli_setpathinfo_ext ( struct cli_state * cli , const char * fname ,
struct timespec create_time ,
struct timespec access_time ,
struct timespec write_time ,
struct timespec change_time ,
2020-06-04 06:48:23 +03:00
uint32_t attr )
2020-03-30 17:47:52 +03:00
{
uint8_t buf [ 40 ] ;
prep_basic_information_buf (
buf ,
create_time ,
access_time ,
write_time ,
change_time ,
2020-06-03 21:01:36 +03:00
attr ) ;
2019-12-01 11:01:13 +03:00
if ( smbXcli_conn_protocol ( cli - > conn ) > = PROTOCOL_SMB2_02 ) {
2020-03-30 17:47:52 +03:00
DATA_BLOB in_data = data_blob_const ( buf , sizeof ( buf ) ) ;
2019-12-01 11:01:13 +03:00
/*
* Split out SMB2 here as we need to select
* the correct info type and level .
*/
return cli_smb2_setpathinfo ( cli ,
2024-05-17 13:23:19 +03:00
fname ,
2024-05-17 13:32:20 +03:00
SMB2_0_INFO_FILE ,
2024-05-17 13:23:19 +03:00
FSCC_FILE_BASIC_INFORMATION ,
& in_data ) ;
2019-12-01 11:01:13 +03:00
}
2020-03-30 17:47:52 +03:00
return cli_setpathinfo (
cli , SMB_FILE_BASIC_INFORMATION , fname , buf , sizeof ( buf ) ) ;
2019-12-01 11:01:13 +03:00
}
2020-03-30 18:54:28 +03:00
struct cli_setfileinfo_ext_state {
uint8_t data [ 40 ] ;
DATA_BLOB in_data ;
} ;
static void cli_setfileinfo_ext_done ( struct tevent_req * subreq ) ;
static void cli_setfileinfo_ext_done2 ( struct tevent_req * subreq ) ;
struct tevent_req * cli_setfileinfo_ext_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum ,
struct timespec create_time ,
struct timespec access_time ,
struct timespec write_time ,
struct timespec change_time ,
2020-06-04 06:58:06 +03:00
uint32_t attr )
2020-03-30 18:54:28 +03:00
{
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_setfileinfo_ext_state * state = NULL ;
req = tevent_req_create (
mem_ctx , & state , struct cli_setfileinfo_ext_state ) ;
if ( req = = NULL ) {
return NULL ;
}
prep_basic_information_buf (
state - > data ,
create_time ,
access_time ,
write_time ,
change_time ,
2020-06-04 06:58:06 +03:00
attr ) ;
2020-03-30 18:54:28 +03:00
if ( smbXcli_conn_protocol ( cli - > conn ) > = PROTOCOL_SMB2_02 ) {
state - > in_data = ( DATA_BLOB ) {
. data = state - > data , . length = sizeof ( state - > data ) ,
} ;
subreq = cli_smb2_set_info_fnum_send (
state ,
ev ,
cli ,
fnum ,
SMB2_0_INFO_FILE ,
2024-05-17 13:23:19 +03:00
FSCC_FILE_BASIC_INFORMATION ,
2020-03-30 18:54:28 +03:00
& state - > in_data ,
2024-05-17 13:23:19 +03:00
0 ) ; /* in_additional_info */
2020-03-30 18:54:28 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback (
subreq , cli_setfileinfo_ext_done2 , req ) ;
return req ;
}
subreq = cli_setfileinfo_send (
state ,
ev ,
cli ,
fnum ,
SMB_FILE_BASIC_INFORMATION ,
state - > data ,
sizeof ( state - > data ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_setfileinfo_ext_done , req ) ;
return req ;
}
static void cli_setfileinfo_ext_done ( struct tevent_req * subreq )
{
NTSTATUS status = cli_setfileinfo_recv ( subreq ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
static void cli_setfileinfo_ext_done2 ( struct tevent_req * subreq )
{
NTSTATUS status = cli_smb2_set_info_fnum_recv ( subreq ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
NTSTATUS cli_setfileinfo_ext_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
NTSTATUS cli_setfileinfo_ext (
struct cli_state * cli ,
uint16_t fnum ,
struct timespec create_time ,
struct timespec access_time ,
struct timespec write_time ,
struct timespec change_time ,
2020-06-04 06:58:06 +03:00
uint32_t attr )
2020-03-30 18:54:28 +03:00
{
TALLOC_CTX * frame = NULL ;
struct tevent_context * ev = NULL ;
struct tevent_req * req = NULL ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
return NT_STATUS_INVALID_PARAMETER ;
}
frame = talloc_stackframe ( ) ;
ev = samba_tevent_context_init ( frame ) ;
if ( ev = = NULL ) {
goto fail ;
}
req = cli_setfileinfo_ext_send (
ev ,
ev ,
cli ,
fnum ,
create_time ,
access_time ,
write_time ,
change_time ,
2020-06-03 21:01:36 +03:00
attr ) ;
2020-03-30 18:54:28 +03:00
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_setfileinfo_ext_recv ( req ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
2000-04-25 18:04:06 +04:00
/****************************************************************************
2007-03-17 03:15:18 +03:00
Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level .
2000-04-25 18:04:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-08-24 02:33:50 +04:00
2010-07-26 11:27:11 +04:00
struct cli_qpathinfo2_state {
2023-08-23 16:07:29 +03:00
struct tevent_context * ev ;
struct cli_state * cli ;
const char * fname ;
2023-04-03 19:31:01 +03:00
struct timespec create_time ;
struct timespec access_time ;
struct timespec write_time ;
struct timespec change_time ;
off_t size ;
uint32_t attr ;
SMB_INO_T ino ;
2023-08-23 16:07:29 +03:00
mode_t mode ;
2010-07-26 11:27:11 +04:00
} ;
2023-04-04 10:36:08 +03:00
static void cli_qpathinfo2_done2 ( struct tevent_req * subreq ) ;
2010-07-26 11:27:11 +04:00
static void cli_qpathinfo2_done ( struct tevent_req * subreq ) ;
2023-08-23 16:07:29 +03:00
static void cli_qpathinfo2_got_reparse ( struct tevent_req * subreq ) ;
2010-07-26 11:27:11 +04:00
struct tevent_req * cli_qpathinfo2_send ( TALLOC_CTX * mem_ctx ,
2013-02-18 12:59:58 +04:00
struct tevent_context * ev ,
2010-07-26 11:27:11 +04:00
struct cli_state * cli ,
const char * fname )
2000-04-25 18:04:06 +04:00
{
2010-07-26 11:27:11 +04:00
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_qpathinfo2_state * state = NULL ;
2000-04-25 18:04:06 +04:00
2010-07-26 11:27:11 +04:00
req = tevent_req_create ( mem_ctx , & state , struct cli_qpathinfo2_state ) ;
if ( req = = NULL ) {
return NULL ;
2007-12-06 00:31:24 +03:00
}
2023-08-23 16:07:29 +03:00
state - > ev = ev ;
state - > cli = cli ;
state - > fname = fname ;
state - > mode = S_IFREG ;
2023-04-04 10:36:08 +03:00
if ( smbXcli_conn_protocol ( cli - > conn ) > = PROTOCOL_SMB2_02 ) {
2023-08-18 17:07:56 +03:00
subreq = cli_smb2_qpathinfo_send ( state ,
ev ,
cli ,
fname ,
FSCC_FILE_ALL_INFORMATION ,
0x60 ,
UINT16_MAX ) ;
2023-04-04 10:36:08 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_qpathinfo2_done2 , req ) ;
return req ;
}
2010-07-26 11:27:11 +04:00
subreq = cli_qpathinfo_send ( state , ev , cli , fname ,
SMB_QUERY_FILE_ALL_INFO ,
2011-08-03 01:05:31 +04:00
68 , CLI_BUFFER_SIZE ) ;
2010-07-26 11:27:11 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_qpathinfo2_done , req ) ;
return req ;
}
2000-04-25 18:04:06 +04:00
2023-04-04 10:36:08 +03:00
static void cli_qpathinfo2_done2 ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq , struct tevent_req ) ;
struct cli_qpathinfo2_state * state =
tevent_req_data ( req , struct cli_qpathinfo2_state ) ;
2023-08-18 17:07:56 +03:00
uint8_t * rdata = NULL ;
uint32_t num_rdata ;
2023-04-04 10:36:08 +03:00
NTSTATUS status ;
2023-08-18 17:07:56 +03:00
status = cli_smb2_qpathinfo_recv ( subreq , state , & rdata , & num_rdata ) ;
2023-04-04 10:36:08 +03:00
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2023-10-04 14:25:21 +03:00
state - > create_time = interpret_long_date ( BVAL ( rdata , 0x0 ) ) ;
state - > access_time = interpret_long_date ( BVAL ( rdata , 0x8 ) ) ;
state - > write_time = interpret_long_date ( BVAL ( rdata , 0x10 ) ) ;
state - > change_time = interpret_long_date ( BVAL ( rdata , 0x18 ) ) ;
2023-08-18 17:07:56 +03:00
state - > attr = PULL_LE_U32 ( rdata , 0x20 ) ;
state - > size = PULL_LE_U64 ( rdata , 0x30 ) ;
state - > ino = PULL_LE_U64 ( rdata , 0x40 ) ;
2023-08-23 16:07:29 +03:00
if ( state - > attr & FILE_ATTRIBUTE_REPARSE_POINT ) {
subreq = cli_get_reparse_data_send ( state ,
state - > ev ,
state - > cli ,
state - > fname ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq ,
cli_qpathinfo2_got_reparse ,
req ) ;
return ;
}
2023-04-04 10:36:08 +03:00
tevent_req_done ( req ) ;
}
2010-07-26 11:27:11 +04:00
static void cli_qpathinfo2_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_qpathinfo2_state * state = tevent_req_data (
req , struct cli_qpathinfo2_state ) ;
2023-04-03 19:31:01 +03:00
uint8_t * data = NULL ;
uint32_t num_data ;
2010-07-26 11:27:11 +04:00
NTSTATUS status ;
2000-04-25 18:04:06 +04:00
2023-04-03 19:31:01 +03:00
status = cli_qpathinfo_recv ( subreq , state , & data , & num_data ) ;
2010-07-26 11:27:11 +04:00
TALLOC_FREE ( subreq ) ;
2023-08-16 12:59:03 +03:00
if ( tevent_req_nterror ( req , status ) ) {
2010-07-26 11:27:11 +04:00
return ;
2000-04-25 18:04:06 +04:00
}
2023-04-03 19:31:01 +03:00
2023-10-04 14:25:21 +03:00
state - > create_time = interpret_long_date ( BVAL ( data , 0 ) ) ;
state - > access_time = interpret_long_date ( BVAL ( data , 8 ) ) ;
state - > write_time = interpret_long_date ( BVAL ( data , 16 ) ) ;
state - > change_time = interpret_long_date ( BVAL ( data , 24 ) ) ;
2023-04-03 19:31:01 +03:00
state - > attr = PULL_LE_U32 ( data , 32 ) ;
state - > size = PULL_LE_U64 ( data , 48 ) ;
/*
* SMB1 qpathinfo2 uses SMB_QUERY_FILE_ALL_INFO which doesn ' t
* return an inode number ( fileid ) . We can ' t change this to
* one of the FILE_ID info levels as only Win2003 and above
* support these [ MS - SMB : 2.2 .2 .3 .1 ] and the SMB1 code needs
* to support older servers .
*/
state - > ino = 0 ;
TALLOC_FREE ( data ) ;
2023-08-23 16:07:29 +03:00
if ( state - > attr & FILE_ATTRIBUTE_REPARSE_POINT ) {
subreq = cli_get_reparse_data_send ( state ,
state - > ev ,
state - > cli ,
state - > fname ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq ,
cli_qpathinfo2_got_reparse ,
req ) ;
return ;
}
tevent_req_done ( req ) ;
}
static void cli_qpathinfo2_got_reparse ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq , struct tevent_req ) ;
struct cli_qpathinfo2_state * state =
tevent_req_data ( req , struct cli_qpathinfo2_state ) ;
uint8_t * data = NULL ;
uint32_t num_data ;
struct reparse_data_buffer reparse = {
. tag = 0 ,
} ;
NTSTATUS status ;
status = cli_get_reparse_data_recv ( subreq , state , & data , & num_data ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
status = reparse_data_buffer_parse ( state , & reparse , data , num_data ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " Ignoring unknown reparse data \n " ) ;
goto done ;
}
switch ( reparse . tag ) {
case IO_REPARSE_TAG_SYMLINK :
state - > mode = S_IFLNK ;
break ;
case IO_REPARSE_TAG_NFS :
switch ( reparse . parsed . nfs . type ) {
case NFS_SPECFILE_LNK :
state - > mode = S_IFLNK ;
break ;
case NFS_SPECFILE_CHR :
state - > mode = S_IFCHR ;
break ;
case NFS_SPECFILE_BLK :
state - > mode = S_IFBLK ;
break ;
case NFS_SPECFILE_FIFO :
state - > mode = S_IFIFO ;
break ;
case NFS_SPECFILE_SOCK :
state - > mode = S_IFSOCK ;
break ;
}
break ;
}
done :
2010-07-26 11:27:11 +04:00
tevent_req_done ( req ) ;
}
2000-04-25 18:04:06 +04:00
2010-07-26 11:27:11 +04:00
NTSTATUS cli_qpathinfo2_recv ( struct tevent_req * req ,
struct timespec * create_time ,
struct timespec * access_time ,
struct timespec * write_time ,
struct timespec * change_time ,
2023-08-23 14:47:20 +03:00
off_t * size ,
uint32_t * pattr ,
SMB_INO_T * ino ,
mode_t * mode )
2010-07-26 11:27:11 +04:00
{
struct cli_qpathinfo2_state * state = tevent_req_data (
req , struct cli_qpathinfo2_state ) ;
NTSTATUS status ;
2000-04-25 18:04:06 +04:00
2010-07-26 11:27:11 +04:00
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
2000-04-25 18:04:06 +04:00
}
2007-12-01 03:13:35 +03:00
2006-08-24 02:33:50 +04:00
if ( create_time ) {
2023-04-03 19:31:01 +03:00
* create_time = state - > create_time ;
2000-04-25 18:04:06 +04:00
}
2006-08-24 02:33:50 +04:00
if ( access_time ) {
2023-04-03 19:31:01 +03:00
* access_time = state - > access_time ;
2000-04-25 18:04:06 +04:00
}
2006-08-24 02:33:50 +04:00
if ( write_time ) {
2023-04-03 19:31:01 +03:00
* write_time = state - > write_time ;
2005-12-25 05:00:21 +03:00
}
2006-08-24 02:33:50 +04:00
if ( change_time ) {
2023-04-03 19:31:01 +03:00
* change_time = state - > change_time ;
2000-04-25 18:04:06 +04:00
}
2020-06-03 21:01:36 +03:00
if ( pattr ) {
2023-04-03 19:31:01 +03:00
* pattr = state - > attr ;
2000-04-25 18:04:06 +04:00
}
if ( size ) {
2023-04-03 19:31:01 +03:00
* size = state - > size ;
2000-04-25 18:04:06 +04:00
}
if ( ino ) {
2023-04-03 19:31:01 +03:00
* ino = state - > ino ;
2000-04-25 18:04:06 +04:00
}
2023-08-23 14:47:20 +03:00
if ( mode ! = NULL ) {
2023-08-23 16:07:29 +03:00
* mode = state - > mode ;
2023-08-23 14:47:20 +03:00
}
2010-07-26 11:27:11 +04:00
return NT_STATUS_OK ;
}
2000-04-25 18:04:06 +04:00
2023-08-23 14:47:20 +03:00
NTSTATUS cli_qpathinfo2 ( struct cli_state * cli ,
const char * fname ,
2010-07-26 11:27:11 +04:00
struct timespec * create_time ,
struct timespec * access_time ,
struct timespec * write_time ,
struct timespec * change_time ,
2023-08-23 14:47:20 +03:00
off_t * size ,
uint32_t * pattr ,
SMB_INO_T * ino ,
mode_t * mode )
2010-07-26 11:27:11 +04:00
{
2023-07-05 12:58:39 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev = NULL ;
struct tevent_req * req = NULL ;
2010-07-26 11:27:11 +04:00
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2012-05-26 13:45:09 +04:00
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
2010-07-26 11:27:11 +04:00
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
2013-02-18 12:08:19 +04:00
ev = samba_tevent_context_init ( frame ) ;
2010-07-26 11:27:11 +04:00
if ( ev = = NULL ) {
goto fail ;
}
req = cli_qpathinfo2_send ( frame , ev , cli , fname ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
2023-08-23 14:47:20 +03:00
status = cli_qpathinfo2_recv ( req ,
create_time ,
access_time ,
write_time ,
change_time ,
size ,
pattr ,
ino ,
mode ) ;
2010-07-26 11:27:11 +04:00
fail :
TALLOC_FREE ( frame ) ;
return status ;
2000-04-25 18:04:06 +04:00
}
2008-01-18 13:08:17 +03:00
/****************************************************************************
Get the stream info
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-26 12:35:15 +04:00
struct cli_qpathinfo_streams_state {
uint32_t num_data ;
uint8_t * data ;
} ;
static void cli_qpathinfo_streams_done ( struct tevent_req * subreq ) ;
2023-08-18 16:47:20 +03:00
static void cli_qpathinfo_streams_done2 ( struct tevent_req * subreq ) ;
2010-07-26 12:35:15 +04:00
struct tevent_req * cli_qpathinfo_streams_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * fname )
2008-01-18 13:08:17 +03:00
{
2010-07-26 12:35:15 +04:00
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_qpathinfo_streams_state * state = NULL ;
2008-01-18 13:08:17 +03:00
2010-07-26 12:35:15 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct cli_qpathinfo_streams_state ) ;
if ( req = = NULL ) {
return NULL ;
2008-01-18 13:08:17 +03:00
}
2023-08-18 16:47:20 +03:00
if ( smbXcli_conn_protocol ( cli - > conn ) > = PROTOCOL_SMB2_02 ) {
subreq = cli_smb2_qpathinfo_send ( state ,
ev ,
cli ,
fname ,
FSCC_FILE_STREAM_INFORMATION ,
0 ,
CLI_BUFFER_SIZE ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq ,
cli_qpathinfo_streams_done2 ,
req ) ;
return req ;
}
2010-07-26 12:35:15 +04:00
subreq = cli_qpathinfo_send ( state , ev , cli , fname ,
SMB_FILE_STREAM_INFORMATION ,
2011-08-03 01:05:31 +04:00
0 , CLI_BUFFER_SIZE ) ;
2010-07-26 12:35:15 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_qpathinfo_streams_done , req ) ;
return req ;
}
2008-01-18 13:08:17 +03:00
2010-07-26 12:35:15 +04:00
static void cli_qpathinfo_streams_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_qpathinfo_streams_state * state = tevent_req_data (
req , struct cli_qpathinfo_streams_state ) ;
NTSTATUS status ;
2008-01-18 13:08:17 +03:00
2010-07-26 12:35:15 +04:00
status = cli_qpathinfo_recv ( subreq , state , & state - > data ,
& state - > num_data ) ;
2023-08-18 16:47:20 +03:00
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
static void cli_qpathinfo_streams_done2 ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq , struct tevent_req ) ;
struct cli_qpathinfo_streams_state * state =
tevent_req_data ( req , struct cli_qpathinfo_streams_state ) ;
NTSTATUS status ;
status = cli_smb2_qpathinfo_recv ( subreq ,
state ,
& state - > data ,
& state - > num_data ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
2010-07-26 12:35:15 +04:00
}
2008-01-18 13:08:17 +03:00
2010-07-26 12:35:15 +04:00
NTSTATUS cli_qpathinfo_streams_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
unsigned int * pnum_streams ,
struct stream_struct * * pstreams )
{
struct cli_qpathinfo_streams_state * state = tevent_req_data (
req , struct cli_qpathinfo_streams_state ) ;
NTSTATUS status ;
2008-01-18 13:08:17 +03:00
2010-07-26 12:35:15 +04:00
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
if ( ! parse_streams_blob ( mem_ctx , state - > data , state - > num_data ,
pnum_streams , pstreams ) ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
2008-01-18 13:08:17 +03:00
}
2010-07-26 12:35:15 +04:00
return NT_STATUS_OK ;
}
2008-01-18 13:08:17 +03:00
2010-07-26 12:35:15 +04:00
NTSTATUS cli_qpathinfo_streams ( struct cli_state * cli , const char * fname ,
TALLOC_CTX * mem_ctx ,
unsigned int * pnum_streams ,
struct stream_struct * * pstreams )
{
2013-08-08 03:46:05 +04:00
TALLOC_CTX * frame = NULL ;
2013-02-18 12:59:58 +04:00
struct tevent_context * ev ;
2010-07-26 12:35:15 +04:00
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2013-08-08 03:46:05 +04:00
frame = talloc_stackframe ( ) ;
2012-05-26 13:45:09 +04:00
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
2010-07-26 12:35:15 +04:00
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
2013-02-18 12:08:19 +04:00
ev = samba_tevent_context_init ( frame ) ;
2010-07-26 12:35:15 +04:00
if ( ev = = NULL ) {
goto fail ;
}
req = cli_qpathinfo_streams_send ( frame , ev , cli , fname ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_qpathinfo_streams_recv ( req , mem_ctx , pnum_streams ,
pstreams ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
2010-07-26 12:08:38 +04:00
}
2013-08-08 02:54:05 +04:00
bool parse_streams_blob ( TALLOC_CTX * mem_ctx , const uint8_t * rdata ,
2010-07-26 12:08:38 +04:00
size_t data_len ,
unsigned int * pnum_streams ,
struct stream_struct * * pstreams )
{
unsigned int num_streams ;
struct stream_struct * streams ;
unsigned int ofs ;
2008-01-18 13:08:17 +03:00
num_streams = 0 ;
streams = NULL ;
ofs = 0 ;
while ( ( data_len > ofs ) & & ( data_len - ofs > = 24 ) ) {
uint32_t nlen , len ;
2008-05-21 01:06:38 +04:00
size_t size ;
2008-01-18 13:08:17 +03:00
void * vstr ;
struct stream_struct * tmp ;
uint8_t * tmp_buf ;
2011-06-07 05:10:15 +04:00
tmp = talloc_realloc ( mem_ctx , streams ,
2008-01-18 13:08:17 +03:00
struct stream_struct ,
num_streams + 1 ) ;
if ( tmp = = NULL ) {
goto fail ;
}
streams = tmp ;
nlen = IVAL ( rdata , ofs + 0x04 ) ;
streams [ num_streams ] . size = IVAL_TO_SMB_OFF_T (
rdata , ofs + 0x08 ) ;
streams [ num_streams ] . alloc_size = IVAL_TO_SMB_OFF_T (
rdata , ofs + 0x10 ) ;
if ( nlen > data_len - ( ofs + 24 ) ) {
goto fail ;
}
/*
* We need to null - terminate src , how do I do this with
* convert_string_talloc ? ?
*/
2011-06-07 05:30:12 +04:00
tmp_buf = talloc_array ( streams , uint8_t , nlen + 2 ) ;
2008-01-18 13:08:17 +03:00
if ( tmp_buf = = NULL ) {
goto fail ;
}
memcpy ( tmp_buf , rdata + ofs + 24 , nlen ) ;
tmp_buf [ nlen ] = 0 ;
tmp_buf [ nlen + 1 ] = 0 ;
2008-04-30 01:36:24 +04:00
if ( ! convert_string_talloc ( streams , CH_UTF16 , CH_UNIX , tmp_buf ,
2011-03-24 02:59:41 +03:00
nlen + 2 , & vstr , & size ) )
2008-04-30 01:36:24 +04:00
{
TALLOC_FREE ( tmp_buf ) ;
2008-01-18 13:08:17 +03:00
goto fail ;
}
2008-04-30 01:36:24 +04:00
TALLOC_FREE ( tmp_buf ) ;
2008-01-18 13:08:17 +03:00
streams [ num_streams ] . name = ( char * ) vstr ;
num_streams + + ;
len = IVAL ( rdata , ofs ) ;
if ( len > data_len - ofs ) {
goto fail ;
}
if ( len = = 0 ) break ;
ofs + = len ;
}
* pnum_streams = num_streams ;
* pstreams = streams ;
return true ;
fail :
TALLOC_FREE ( streams ) ;
return false ;
}
2002-02-21 07:25:17 +03:00
/****************************************************************************
2007-03-17 03:15:18 +03:00
Send a qfileinfo QUERY_FILE_NAME_INFO call .
2002-02-21 07:25:17 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-03-17 03:15:18 +03:00
2020-05-28 19:24:17 +03:00
struct cli_qfileinfo_basic_state {
uint32_t attr ;
off_t size ;
struct timespec create_time ;
struct timespec access_time ;
struct timespec write_time ;
struct timespec change_time ;
SMB_INO_T ino ;
} ;
2007-03-17 03:15:18 +03:00
2020-05-28 19:24:17 +03:00
static void cli_qfileinfo_basic_done ( struct tevent_req * subreq ) ;
2020-06-04 09:38:31 +03:00
static void cli_qfileinfo_basic_doneE ( struct tevent_req * subreq ) ;
2020-05-28 19:24:17 +03:00
struct tevent_req * cli_qfileinfo_basic_send (
TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
uint16_t fnum )
2000-04-25 18:04:06 +04:00
{
2020-05-28 19:24:17 +03:00
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_qfileinfo_basic_state * state = NULL ;
2000-04-25 18:04:06 +04:00
2020-05-28 19:24:17 +03:00
req = tevent_req_create (
mem_ctx , & state , struct cli_qfileinfo_basic_state ) ;
if ( req = = NULL ) {
return NULL ;
2013-08-08 03:47:21 +04:00
}
2020-06-04 09:38:31 +03:00
if ( ( smbXcli_conn_protocol ( cli - > conn ) < PROTOCOL_LANMAN2 ) | |
cli - > win95 ) {
/*
* According to
* https : //docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/3d9d8f3e-dc70-410d-a3fc-6f4a881e8cab
* SMB_COM_TRANSACTION2 used in cli_qfileinfo_send ( )
* further down was introduced with the LAN Manager
* 1.2 dialect , which we encode as PROTOCOL_LANMAN2 .
*
* The " win95 " check was introduced with commit
* 27e5850 fd3e1c8 in 1998. Hard to check these days ,
* but leave it in .
*
* Use a lowerlevel fallback in both cases .
*/
subreq = cli_getattrE_send ( state , ev , cli , fnum ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback (
subreq , cli_qfileinfo_basic_doneE , req ) ;
return req ;
2010-10-24 00:37:16 +04:00
}
2000-04-25 18:04:06 +04:00
2024-05-09 11:12:14 +03:00
subreq = cli_qfileinfo_send ( state ,
ev ,
cli ,
fnum ,
FSCC_FILE_ALL_INFORMATION , /* level */
68 , /* min_rdata */
CLI_BUFFER_SIZE ) ; /* max_rdata */
2020-05-28 19:24:17 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_qfileinfo_basic_done , req ) ;
return req ;
}
static void cli_qfileinfo_basic_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_qfileinfo_basic_state * state = tevent_req_data (
req , struct cli_qfileinfo_basic_state ) ;
uint8_t * rdata ;
uint32_t num_rdata ;
NTSTATUS status ;
status = cli_qfileinfo_recv (
subreq , state , NULL , & rdata , & num_rdata ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2023-10-04 14:25:21 +03:00
state - > create_time = interpret_long_date ( BVAL ( rdata , 0 ) ) ;
state - > access_time = interpret_long_date ( BVAL ( rdata , 8 ) ) ;
state - > write_time = interpret_long_date ( BVAL ( rdata , 16 ) ) ;
state - > change_time = interpret_long_date ( BVAL ( rdata , 24 ) ) ;
2020-05-28 19:24:17 +03:00
state - > attr = PULL_LE_U32 ( rdata , 32 ) ;
state - > size = PULL_LE_U64 ( rdata , 48 ) ;
state - > ino = PULL_LE_U32 ( rdata , 64 ) ;
TALLOC_FREE ( rdata ) ;
tevent_req_done ( req ) ;
}
2020-06-04 09:38:31 +03:00
static void cli_qfileinfo_basic_doneE ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_qfileinfo_basic_state * state = tevent_req_data (
req , struct cli_qfileinfo_basic_state ) ;
NTSTATUS status ;
status = cli_getattrE_recv (
subreq ,
& state - > attr ,
& state - > size ,
& state - > change_time . tv_sec ,
& state - > access_time . tv_sec ,
& state - > write_time . tv_sec ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
2020-05-28 19:24:17 +03:00
NTSTATUS cli_qfileinfo_basic_recv (
struct tevent_req * req ,
uint32_t * attr ,
off_t * size ,
struct timespec * create_time ,
struct timespec * access_time ,
struct timespec * write_time ,
struct timespec * change_time ,
SMB_INO_T * ino )
{
struct cli_qfileinfo_basic_state * state = tevent_req_data (
req , struct cli_qfileinfo_basic_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
2010-10-24 00:37:16 +04:00
return status ;
2000-04-25 18:04:06 +04:00
}
2020-05-28 19:24:17 +03:00
if ( create_time ! = NULL ) {
* create_time = state - > create_time ;
2000-04-25 18:04:06 +04:00
}
2020-05-28 19:24:17 +03:00
if ( access_time ! = NULL ) {
* access_time = state - > access_time ;
2000-04-25 18:04:06 +04:00
}
2020-05-28 19:24:17 +03:00
if ( write_time ! = NULL ) {
* write_time = state - > write_time ;
2000-04-25 18:04:06 +04:00
}
2020-05-28 19:24:17 +03:00
if ( change_time ! = NULL ) {
* change_time = state - > change_time ;
2000-04-25 18:04:06 +04:00
}
2020-05-28 19:24:17 +03:00
if ( attr ! = NULL ) {
* attr = state - > attr ;
2000-04-25 18:04:06 +04:00
}
2020-05-28 19:24:17 +03:00
if ( size ! = NULL ) {
* size = state - > size ;
2000-04-25 18:04:06 +04:00
}
if ( ino ) {
2020-05-28 19:24:17 +03:00
* ino = state - > ino ;
2000-04-25 18:04:06 +04:00
}
2010-10-24 00:37:16 +04:00
return NT_STATUS_OK ;
2000-04-25 18:04:06 +04:00
}
2020-05-28 19:24:17 +03:00
/****************************************************************************
Send a qfileinfo call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS cli_qfileinfo_basic (
struct cli_state * cli ,
uint16_t fnum ,
uint32_t * attr ,
off_t * size ,
struct timespec * create_time ,
struct timespec * access_time ,
struct timespec * write_time ,
struct timespec * change_time ,
SMB_INO_T * ino )
{
TALLOC_CTX * frame = NULL ;
struct tevent_context * ev = NULL ;
struct tevent_req * req = NULL ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
frame = talloc_stackframe ( ) ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
ev = samba_tevent_context_init ( frame ) ;
if ( ev = = NULL ) {
goto fail ;
}
req = cli_qfileinfo_basic_send ( frame , ev , cli , fnum ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_qfileinfo_basic_recv (
req ,
attr ,
size ,
create_time ,
access_time ,
write_time ,
change_time ,
ino ) ;
2020-06-04 16:11:24 +03:00
/* cli_smb2_query_info_fnum_recv doesn't set this */
cli - > raw_status = status ;
2020-05-28 19:24:17 +03:00
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
2000-04-25 18:04:06 +04:00
2005-02-23 20:29:28 +03:00
/****************************************************************************
2007-03-09 02:54:57 +03:00
Send a qpathinfo BASIC_INFO call .
2005-02-23 20:29:28 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-03-09 02:54:57 +03:00
2010-07-26 11:41:25 +04:00
struct cli_qpathinfo_basic_state {
uint32_t num_data ;
uint8_t * data ;
} ;
static void cli_qpathinfo_basic_done ( struct tevent_req * subreq ) ;
struct tevent_req * cli_qpathinfo_basic_send ( TALLOC_CTX * mem_ctx ,
2013-02-18 12:59:58 +04:00
struct tevent_context * ev ,
2010-07-26 11:41:25 +04:00
struct cli_state * cli ,
const char * fname )
2005-02-23 20:29:28 +03:00
{
2010-07-26 11:41:25 +04:00
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_qpathinfo_basic_state * state = NULL ;
2007-12-01 03:13:35 +03:00
2010-07-26 11:41:25 +04:00
req = tevent_req_create ( mem_ctx , & state ,
struct cli_qpathinfo_basic_state ) ;
if ( req = = NULL ) {
return NULL ;
2007-12-01 03:13:35 +03:00
}
2010-07-26 11:41:25 +04:00
subreq = cli_qpathinfo_send ( state , ev , cli , fname ,
SMB_QUERY_FILE_BASIC_INFO ,
2011-08-03 01:05:31 +04:00
36 , CLI_BUFFER_SIZE ) ;
2010-07-26 11:41:25 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
2007-12-01 03:13:35 +03:00
}
2010-07-26 11:41:25 +04:00
tevent_req_set_callback ( subreq , cli_qpathinfo_basic_done , req ) ;
return req ;
}
2005-02-23 20:29:28 +03:00
2010-07-26 11:41:25 +04:00
static void cli_qpathinfo_basic_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_qpathinfo_basic_state * state = tevent_req_data (
req , struct cli_qpathinfo_basic_state ) ;
NTSTATUS status ;
status = cli_qpathinfo_recv ( subreq , state , & state - > data ,
& state - > num_data ) ;
TALLOC_FREE ( subreq ) ;
2023-08-16 12:59:03 +03:00
if ( tevent_req_nterror ( req , status ) ) {
2010-07-26 11:41:25 +04:00
return ;
2007-12-06 00:31:24 +03:00
}
2010-07-26 11:41:25 +04:00
tevent_req_done ( req ) ;
}
2007-12-06 00:31:24 +03:00
2010-07-26 11:41:25 +04:00
NTSTATUS cli_qpathinfo_basic_recv ( struct tevent_req * req ,
2015-05-10 02:59:45 +03:00
SMB_STRUCT_STAT * sbuf , uint32_t * attributes )
2010-07-26 11:41:25 +04:00
{
struct cli_qpathinfo_basic_state * state = tevent_req_data (
req , struct cli_qpathinfo_basic_state ) ;
NTSTATUS status ;
2005-02-23 20:29:28 +03:00
2010-07-26 11:41:25 +04:00
if ( tevent_req_is_nterror ( req , & status ) ) {
2010-02-07 16:07:17 +03:00
return status ;
2005-02-23 20:29:28 +03:00
}
2023-10-04 14:25:21 +03:00
sbuf - > st_ex_btime = interpret_long_date ( BVAL ( state - > data , 0 ) ) ;
sbuf - > st_ex_atime = interpret_long_date ( BVAL ( state - > data , 8 ) ) ;
sbuf - > st_ex_mtime = interpret_long_date ( BVAL ( state - > data , 16 ) ) ;
sbuf - > st_ex_ctime = interpret_long_date ( BVAL ( state - > data , 24 ) ) ;
2010-07-26 11:41:25 +04:00
* attributes = IVAL ( state - > data , 32 ) ;
return NT_STATUS_OK ;
}
2007-12-01 03:13:35 +03:00
2010-07-26 11:41:25 +04:00
NTSTATUS cli_qpathinfo_basic ( struct cli_state * cli , const char * name ,
2015-05-10 02:59:45 +03:00
SMB_STRUCT_STAT * sbuf , uint32_t * attributes )
2010-07-26 11:41:25 +04:00
{
2013-08-08 21:52:02 +04:00
TALLOC_CTX * frame = NULL ;
2013-02-18 12:59:58 +04:00
struct tevent_context * ev ;
2010-07-26 11:41:25 +04:00
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2007-12-01 03:13:35 +03:00
2013-08-08 21:52:02 +04:00
if ( smbXcli_conn_protocol ( cli - > conn ) > = PROTOCOL_SMB2_02 ) {
return cli_smb2_qpathinfo_basic ( cli ,
name ,
sbuf ,
attributes ) ;
}
frame = talloc_stackframe ( ) ;
2012-05-26 13:45:09 +04:00
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
2010-07-26 11:41:25 +04:00
/*
* Can ' t use sync call while an async call is in flight
*/
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
2013-02-18 12:08:19 +04:00
ev = samba_tevent_context_init ( frame ) ;
2010-07-26 11:41:25 +04:00
if ( ev = = NULL ) {
goto fail ;
}
req = cli_qpathinfo_basic_send ( frame , ev , cli , name ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_qpathinfo_basic_recv ( req , sbuf , attributes ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
2005-02-23 20:29:28 +03:00
}
2001-09-25 08:25:49 +04:00
/****************************************************************************
2007-03-17 03:15:18 +03:00
Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call .
2001-09-25 08:25:49 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-03-17 03:15:18 +03:00
2001-09-25 08:25:49 +04:00
NTSTATUS cli_qpathinfo_alt_name ( struct cli_state * cli , const char * fname , fstring alt_name )
{
2011-01-09 21:44:13 +03:00
uint8_t * rdata ;
uint32_t num_rdata ;
2003-03-18 01:40:37 +03:00
unsigned int len ;
2011-01-09 21:44:13 +03:00
char * converted = NULL ;
size_t converted_size = 0 ;
NTSTATUS status ;
2007-12-06 00:31:24 +03:00
2011-01-09 21:44:13 +03:00
status = cli_qpathinfo ( talloc_tos ( ) , cli , fname ,
SMB_QUERY_FILE_ALT_NAME_INFO ,
2011-08-03 01:05:31 +04:00
4 , CLI_BUFFER_SIZE , & rdata , & num_rdata ) ;
2011-01-09 21:44:13 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2001-09-25 08:25:49 +04:00
}
len = IVAL ( rdata , 0 ) ;
2011-01-09 21:44:13 +03:00
if ( len > num_rdata - 4 ) {
2001-09-25 08:25:49 +04:00
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
2011-01-09 21:44:13 +03:00
/* The returned data is a pushed string, not raw data. */
if ( ! convert_string_talloc ( talloc_tos ( ) ,
2012-05-26 14:14:51 +04:00
smbXcli_conn_use_unicode ( cli - > conn ) ? CH_UTF16LE : CH_DOS ,
2011-01-09 21:44:13 +03:00
CH_UNIX ,
rdata + 4 ,
len ,
& converted ,
2011-03-24 02:59:41 +03:00
& converted_size ) ) {
2011-01-09 21:44:13 +03:00
return NT_STATUS_NO_MEMORY ;
}
fstrcpy ( alt_name , converted ) ;
2001-09-25 08:25:49 +04:00
2011-01-09 21:44:13 +03:00
TALLOC_FREE ( converted ) ;
TALLOC_FREE ( rdata ) ;
2001-09-25 08:25:49 +04:00
return NT_STATUS_OK ;
}
2013-10-11 12:52:21 +04:00
/****************************************************************************
2020-06-04 17:15:56 +03:00
Send a qpathinfo SMB_QUERY_FILE_STANDARD_INFO call .
2013-10-11 12:52:21 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2024-08-05 16:10:00 +03:00
static NTSTATUS cli_qpathinfo_standard ( struct cli_state * cli ,
const char * fname ,
uint64_t * allocated ,
uint64_t * size ,
uint32_t * nlinks ,
bool * is_del_pending ,
bool * is_dir )
2013-10-11 12:52:21 +04:00
{
uint8_t * rdata ;
uint32_t num_rdata ;
NTSTATUS status ;
if ( smbXcli_conn_protocol ( cli - > conn ) > = PROTOCOL_SMB2_02 ) {
return NT_STATUS_NOT_IMPLEMENTED ;
}
status = cli_qpathinfo ( talloc_tos ( ) , cli , fname ,
SMB_QUERY_FILE_STANDARD_INFO ,
24 , CLI_BUFFER_SIZE , & rdata , & num_rdata ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( allocated ) {
* allocated = BVAL ( rdata , 0 ) ;
}
if ( size ) {
* size = BVAL ( rdata , 8 ) ;
}
if ( nlinks ) {
* nlinks = IVAL ( rdata , 16 ) ;
}
if ( is_del_pending ) {
* is_del_pending = CVAL ( rdata , 20 ) ;
}
if ( is_dir ) {
* is_dir = CVAL ( rdata , 20 ) ;
}
TALLOC_FREE ( rdata ) ;
return NT_STATUS_OK ;
}
2013-10-11 12:53:45 +04:00
2013-10-14 13:43:45 +04:00
/* like cli_qpathinfo2 but do not use SMB_QUERY_FILE_ALL_INFO with smb1 */
2013-10-11 12:53:45 +04:00
NTSTATUS cli_qpathinfo3 ( struct cli_state * cli , const char * fname ,
struct timespec * create_time ,
struct timespec * access_time ,
struct timespec * write_time ,
struct timespec * change_time ,
2020-06-03 23:36:05 +03:00
off_t * size , uint32_t * pattr ,
2013-10-11 12:53:45 +04:00
SMB_INO_T * ino )
{
NTSTATUS status = NT_STATUS_OK ;
2014-10-30 18:12:17 +03:00
SMB_STRUCT_STAT st = { 0 } ;
2019-08-13 17:55:13 +03:00
uint32_t attr = 0 ;
2013-10-11 12:53:45 +04:00
uint64_t pos ;
2013-10-14 13:43:45 +04:00
if ( smbXcli_conn_protocol ( cli - > conn ) > = PROTOCOL_SMB2_02 ) {
2020-06-03 23:36:05 +03:00
/*
* NB . cli_qpathinfo2 ( ) checks pattr is valid before
* storing a value into it , so we don ' t need to use
* an intermediate attr variable as below but can
* pass pattr directly .
*/
2023-08-23 14:47:20 +03:00
return cli_qpathinfo2 ( cli ,
fname ,
create_time ,
access_time ,
write_time ,
change_time ,
size ,
pattr ,
ino ,
NULL ) ;
2013-10-14 13:43:45 +04:00
}
2020-06-03 21:01:36 +03:00
if ( create_time | | access_time | | write_time | | change_time | | pattr ) {
2020-06-03 23:36:05 +03:00
/*
* cli_qpathinfo_basic ( ) always indirects the passed
* in pointers so we use intermediate variables to
* collect all of them before assigning any requested
* below .
*/
2013-10-11 12:53:45 +04:00
status = cli_qpathinfo_basic ( cli , fname , & st , & attr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
}
if ( size ) {
status = cli_qpathinfo_standard ( cli , fname ,
NULL , & pos , NULL , NULL , NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
* size = pos ;
}
if ( create_time ) {
* create_time = st . st_ex_btime ;
}
if ( access_time ) {
* access_time = st . st_ex_atime ;
}
if ( write_time ) {
* write_time = st . st_ex_mtime ;
}
if ( change_time ) {
* change_time = st . st_ex_ctime ;
}
2020-06-03 21:01:36 +03:00
if ( pattr ) {
* pattr = attr ;
2013-10-11 12:53:45 +04:00
}
if ( ino ) {
* ino = 0 ;
}
return NT_STATUS_OK ;
}