2011-06-23 18:49:17 +04:00
/*
* Unix SMB / CIFS implementation .
* Client implementation of setting symlinks using reparse points
* Copyright ( C ) Volker Lendecke 2011
*
* 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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "system/filesys.h"
# include "libsmb/libsmb.h"
# include "../lib/util/tevent_ntstatus.h"
# include "async_smb.h"
# include "libsmb/clirap.h"
# include "trans2.h"
# include "libcli/security/secdesc.h"
# include "libcli/security/security.h"
2012-05-26 13:45:09 +04:00
# include "../libcli/smb/smbXcli_base.h"
2023-07-07 12:40:19 +03:00
# include "libcli/smb/reparse.h"
2011-06-23 18:49:17 +04:00
2023-09-21 02:54:40 +03:00
struct cli_create_reparse_point_state {
2011-06-23 18:49:17 +04:00
struct tevent_context * ev ;
struct cli_state * cli ;
2023-09-21 02:54:40 +03:00
DATA_BLOB reparse_blob ;
2011-06-23 18:49:17 +04:00
uint16_t fnum ;
NTSTATUS set_reparse_status ;
} ;
2023-09-21 02:54:40 +03:00
static void cli_create_reparse_point_opened ( struct tevent_req * subreq ) ;
static void cli_create_reparse_point_done ( struct tevent_req * subreq ) ;
static void cli_create_reparse_point_doc_done ( struct tevent_req * subreq ) ;
static void cli_create_reparse_point_closed ( struct tevent_req * subreq ) ;
2011-06-23 18:49:17 +04:00
2023-09-21 02:54:40 +03:00
struct tevent_req * cli_create_reparse_point_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * fname ,
DATA_BLOB reparse_blob )
2011-06-23 18:49:17 +04:00
{
2023-09-21 02:54:40 +03:00
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_create_reparse_point_state * state = NULL ;
2011-06-23 18:49:17 +04:00
2023-09-21 02:54:40 +03:00
req = tevent_req_create ( mem_ctx ,
& state ,
struct cli_create_reparse_point_state ) ;
2011-06-23 18:49:17 +04:00
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
2023-09-21 02:54:40 +03:00
state - > reparse_blob = reparse_blob ;
2011-06-23 18:49:17 +04:00
2023-09-21 02:54:40 +03:00
/*
* The create arguments were taken from a Windows - > Windows
* symlink create call .
*/
2011-06-23 18:49:17 +04:00
subreq = cli_ntcreate_send (
2023-09-21 02:54:40 +03:00
state ,
ev ,
cli ,
fname ,
0 ,
SYNCHRONIZE_ACCESS | DELETE_ACCESS | FILE_READ_ATTRIBUTES |
FILE_WRITE_ATTRIBUTES ,
FILE_ATTRIBUTE_NORMAL ,
FILE_SHARE_NONE ,
FILE_CREATE ,
FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT |
FILE_NON_DIRECTORY_FILE ,
SMB2_IMPERSONATION_IMPERSONATION ,
0 ) ;
2011-06-23 18:49:17 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2023-09-21 02:54:40 +03:00
tevent_req_set_callback ( subreq , cli_create_reparse_point_opened , req ) ;
2011-06-23 18:49:17 +04:00
return req ;
}
2023-09-21 02:54:40 +03:00
static void cli_create_reparse_point_opened ( struct tevent_req * subreq )
2011-06-23 18:49:17 +04:00
{
2023-09-21 02:54:40 +03:00
struct tevent_req * req =
tevent_req_callback_data ( subreq , struct tevent_req ) ;
struct cli_create_reparse_point_state * state =
tevent_req_data ( req , struct cli_create_reparse_point_state ) ;
2011-06-23 18:49:17 +04:00
NTSTATUS status ;
2014-05-09 07:55:57 +04:00
status = cli_ntcreate_recv ( subreq , & state - > fnum , NULL ) ;
2011-06-23 18:49:17 +04:00
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2023-09-21 02:54:40 +03:00
subreq = cli_fsctl_send ( state ,
state - > ev ,
state - > cli ,
state - > fnum ,
FSCTL_SET_REPARSE_POINT ,
& state - > reparse_blob ,
0 ) ;
2011-06-23 18:49:17 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
2023-09-21 02:54:40 +03:00
tevent_req_set_callback ( subreq , cli_create_reparse_point_done , req ) ;
2011-06-23 18:49:17 +04:00
}
2023-09-21 02:54:40 +03:00
static void cli_create_reparse_point_done ( struct tevent_req * subreq )
2011-06-23 18:49:17 +04:00
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2023-09-21 02:54:40 +03:00
struct cli_create_reparse_point_state * state =
tevent_req_data ( req , struct cli_create_reparse_point_state ) ;
2011-06-23 18:49:17 +04:00
2022-09-29 13:47:45 +03:00
state - > set_reparse_status = cli_fsctl_recv ( subreq , NULL , NULL ) ;
2011-06-23 18:49:17 +04:00
TALLOC_FREE ( subreq ) ;
if ( NT_STATUS_IS_OK ( state - > set_reparse_status ) ) {
2023-10-07 13:13:09 +03:00
subreq = cli_close_send ( state ,
state - > ev ,
state - > cli ,
state - > fnum ,
0 ) ;
2011-06-23 18:49:17 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
2023-09-21 02:54:40 +03:00
tevent_req_set_callback ( subreq ,
cli_create_reparse_point_closed ,
req ) ;
2011-06-23 18:49:17 +04:00
return ;
}
subreq = cli_nt_delete_on_close_send (
state , state - > ev , state - > cli , state - > fnum , true ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
2023-09-21 02:54:40 +03:00
tevent_req_set_callback ( subreq ,
cli_create_reparse_point_doc_done ,
req ) ;
2011-06-23 18:49:17 +04:00
}
2023-09-21 02:54:40 +03:00
static void cli_create_reparse_point_doc_done ( struct tevent_req * subreq )
2011-06-23 18:49:17 +04:00
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2023-09-21 02:54:40 +03:00
struct cli_create_reparse_point_state * state =
tevent_req_data ( req , struct cli_create_reparse_point_state ) ;
2011-06-23 18:49:17 +04:00
/*
* Ignore status , we can ' t do much anyway in case of failure
*/
2012-02-18 02:12:40 +04:00
( void ) cli_nt_delete_on_close_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
2023-10-07 13:13:09 +03:00
subreq = cli_close_send ( state , state - > ev , state - > cli , state - > fnum , 0 ) ;
2011-06-23 18:49:17 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
2023-09-21 02:54:40 +03:00
tevent_req_set_callback ( subreq , cli_create_reparse_point_closed , req ) ;
2011-06-23 18:49:17 +04:00
}
2023-09-21 02:54:40 +03:00
static void cli_create_reparse_point_closed ( struct tevent_req * subreq )
2011-06-23 18:49:17 +04:00
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2023-09-21 02:54:40 +03:00
struct cli_create_reparse_point_state * state =
tevent_req_data ( req , struct cli_create_reparse_point_state ) ;
2011-06-23 18:49:17 +04:00
NTSTATUS status ;
status = cli_close_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
if ( tevent_req_nterror ( req , state - > set_reparse_status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
2023-09-21 02:54:40 +03:00
NTSTATUS cli_create_reparse_point_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
struct cli_symlink_state {
uint8_t dummy ;
} ;
static void cli_symlink_done ( struct tevent_req * subreq ) ;
struct tevent_req * cli_symlink_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * link_target ,
const char * newpath ,
uint32_t flags )
{
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_symlink_state * state = NULL ;
2023-09-21 17:23:41 +03:00
struct reparse_data_buffer reparse_buf = {
. tag = IO_REPARSE_TAG_SYMLINK ,
. parsed . lnk . substitute_name =
discard_const_p ( char , link_target ) ,
. parsed . lnk . print_name = discard_const_p ( char , link_target ) ,
. parsed . lnk . flags = flags ,
} ;
uint8_t * buf ;
ssize_t buflen ;
2023-09-21 02:54:40 +03:00
req = tevent_req_create ( mem_ctx , & state , struct cli_symlink_state ) ;
if ( req = = NULL ) {
return NULL ;
}
2023-09-21 17:23:41 +03:00
buflen = reparse_data_buffer_marshall ( & reparse_buf , NULL , 0 ) ;
if ( buflen = = - 1 ) {
2023-09-21 02:54:40 +03:00
tevent_req_oom ( req ) ;
return tevent_req_post ( req , ev ) ;
}
2023-09-21 17:23:41 +03:00
buf = talloc_array ( state , uint8_t , buflen ) ;
if ( tevent_req_nomem ( buf , req ) ) {
return tevent_req_post ( req , ev ) ;
}
buflen = reparse_data_buffer_marshall ( & reparse_buf , buf , buflen ) ;
if ( buflen ! = talloc_array_length ( buf ) ) {
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
return tevent_req_post ( req , ev ) ;
}
subreq = cli_create_reparse_point_send ( state ,
ev ,
cli ,
newpath ,
( DATA_BLOB ) {
. data = buf ,
. length = buflen ,
} ) ;
2023-09-21 02:54:40 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_symlink_done , req ) ;
return req ;
}
static void cli_symlink_done ( struct tevent_req * subreq )
{
NTSTATUS status = cli_symlink_recv ( subreq ) ;
tevent_req_simple_finish_ntstatus ( subreq , status ) ;
}
2011-06-23 18:49:17 +04:00
NTSTATUS cli_symlink_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
2017-11-30 00:16:43 +03:00
NTSTATUS cli_symlink ( struct cli_state * cli , const char * link_target ,
2011-06-23 18:49:17 +04:00
const char * newname , uint32_t flags )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2013-02-18 12:59:58 +04:00
struct tevent_context * ev ;
2011-06-23 18:49:17 +04:00
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2012-05-26 13:45:09 +04:00
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
2011-06-23 18:49:17 +04:00
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
2013-02-18 12:08:19 +04:00
ev = samba_tevent_context_init ( frame ) ;
2011-06-23 18:49:17 +04:00
if ( ev = = NULL ) {
goto fail ;
}
2017-11-30 00:16:43 +03:00
req = cli_symlink_send ( frame , ev , cli , link_target , newname , flags ) ;
2011-06-23 18:49:17 +04:00
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_symlink_recv ( req ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
2011-06-30 17:06:46 +04:00
2023-07-06 18:34:31 +03:00
struct cli_get_reparse_data_state {
struct tevent_context * ev ;
struct cli_state * cli ;
uint16_t fnum ;
NTSTATUS get_reparse_status ;
uint8_t * data ;
uint32_t datalen ;
} ;
static void cli_get_reparse_data_opened ( struct tevent_req * subreq ) ;
static void cli_get_reparse_data_done ( struct tevent_req * subreq ) ;
static void cli_get_reparse_data_closed ( struct tevent_req * subreq ) ;
struct tevent_req * cli_get_reparse_data_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * fname )
{
struct tevent_req * req = NULL , * subreq = NULL ;
struct cli_get_reparse_data_state * state = NULL ;
req = tevent_req_create ( mem_ctx ,
& state ,
struct cli_get_reparse_data_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
subreq = cli_ntcreate_send ( state ,
ev ,
cli ,
fname ,
0 ,
FILE_READ_ATTRIBUTES | FILE_READ_EA ,
0 ,
FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE ,
FILE_OPEN ,
FILE_OPEN_REPARSE_POINT ,
SMB2_IMPERSONATION_IMPERSONATION ,
0 ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_get_reparse_data_opened , req ) ;
return req ;
}
static void cli_get_reparse_data_opened ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq , struct tevent_req ) ;
struct cli_get_reparse_data_state * state =
tevent_req_data ( req , struct cli_get_reparse_data_state ) ;
NTSTATUS status ;
status = cli_ntcreate_recv ( subreq , & state - > fnum , NULL ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
subreq = cli_fsctl_send ( state ,
state - > ev ,
state - > cli ,
state - > fnum ,
FSCTL_GET_REPARSE_POINT ,
NULL ,
65536 ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_get_reparse_data_done , req ) ;
}
static void cli_get_reparse_data_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq , struct tevent_req ) ;
struct cli_get_reparse_data_state * state =
tevent_req_data ( req , struct cli_get_reparse_data_state ) ;
DATA_BLOB out = {
. data = NULL ,
} ;
state - > get_reparse_status = cli_fsctl_recv ( subreq , state , & out ) ;
TALLOC_FREE ( subreq ) ;
if ( NT_STATUS_IS_OK ( state - > get_reparse_status ) ) {
state - > data = out . data ;
state - > datalen = out . length ;
}
2023-10-07 13:13:09 +03:00
subreq = cli_close_send ( state , state - > ev , state - > cli , state - > fnum , 0 ) ;
2023-07-06 18:34:31 +03:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , cli_get_reparse_data_closed , req ) ;
}
static void cli_get_reparse_data_closed ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq , struct tevent_req ) ;
struct cli_get_reparse_data_state * state =
tevent_req_data ( req , struct cli_get_reparse_data_state ) ;
NTSTATUS status ;
status = cli_close_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
if ( tevent_req_nterror ( req , state - > get_reparse_status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS cli_get_reparse_data_recv ( struct tevent_req * req ,
TALLOC_CTX * mem_ctx ,
uint8_t * * _data ,
uint32_t * _datalen )
{
struct cli_get_reparse_data_state * state =
tevent_req_data ( req , struct cli_get_reparse_data_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
* _data = talloc_move ( mem_ctx , & state - > data ) ;
* _datalen = state - > datalen ;
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
NTSTATUS cli_get_reparse_data ( struct cli_state * cli ,
const char * fname ,
TALLOC_CTX * mem_ctx ,
uint8_t * * _data ,
uint32_t * _datalen )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
ev = samba_tevent_context_init ( frame ) ;
if ( ev = = NULL ) {
goto fail ;
}
req = cli_get_reparse_data_send ( frame , ev , cli , fname ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_get_reparse_data_recv ( req , mem_ctx , _data , _datalen ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
2011-06-30 17:06:46 +04:00
struct cli_readlink_state {
struct tevent_context * ev ;
struct cli_state * cli ;
uint16_t fnum ;
uint16_t setup [ 4 ] ;
uint8_t * data ;
uint32_t num_data ;
2022-10-12 21:35:10 +03:00
char * target ;
2011-06-30 17:06:46 +04:00
} ;
2022-10-12 21:35:10 +03:00
static void cli_readlink_posix1_done ( struct tevent_req * subreq ) ;
2011-06-30 17:06:46 +04:00
static void cli_readlink_got_reparse_data ( struct tevent_req * subreq ) ;
struct tevent_req * cli_readlink_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct cli_state * cli ,
const char * fname )
{
struct tevent_req * req , * subreq ;
struct cli_readlink_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct cli_readlink_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
2022-10-12 21:35:10 +03:00
if ( cli - > requested_posix_capabilities ! = 0 ) {
/*
* Only happens for negotiated SMB1 posix caps
*/
subreq = cli_posix_readlink_send ( state , ev , cli , fname ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , cli_readlink_posix1_done , req ) ;
return req ;
}
2023-07-06 18:34:31 +03:00
subreq = cli_get_reparse_data_send ( state , ev , cli , fname ) ;
2011-06-30 17:06:46 +04:00
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
2023-07-06 18:34:31 +03:00
tevent_req_set_callback ( subreq , cli_readlink_got_reparse_data , req ) ;
2011-06-30 17:06:46 +04:00
return req ;
}
2022-10-12 21:35:10 +03:00
static void cli_readlink_posix1_done ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct cli_readlink_state * state = tevent_req_data (
req , struct cli_readlink_state ) ;
NTSTATUS status ;
status = cli_posix_readlink_recv ( subreq , state , & state - > target ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
2011-06-30 17:06:46 +04:00
static void cli_readlink_got_reparse_data ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
2022-08-14 17:13:32 +03:00
struct cli_readlink_state * state = tevent_req_data (
req , struct cli_readlink_state ) ;
2011-06-30 17:06:46 +04:00
NTSTATUS status ;
2023-07-06 18:34:31 +03:00
status = cli_get_reparse_data_recv ( subreq ,
state ,
& state - > data ,
& state - > num_data ) ;
2011-06-30 17:06:46 +04:00
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
tevent_req_done ( req ) ;
}
NTSTATUS cli_readlink_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
char * * psubstitute_name , char * * pprint_name ,
uint32_t * pflags )
{
struct cli_readlink_state * state = tevent_req_data (
req , struct cli_readlink_state ) ;
2023-07-07 12:40:19 +03:00
struct reparse_data_buffer buf = {
. tag = 0 ,
} ;
2011-06-30 17:06:46 +04:00
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
2022-10-12 21:35:10 +03:00
if ( state - > target ! = NULL ) {
/*
* SMB1 posix version
*/
if ( psubstitute_name ! = NULL ) {
* psubstitute_name = talloc_move (
mem_ctx , & state - > target ) ;
}
if ( pprint_name ! = NULL ) {
* pprint_name = NULL ;
}
if ( pflags ! = NULL ) {
* pflags = 0 ;
}
return NT_STATUS_OK ;
}
2023-07-07 12:40:19 +03:00
status = reparse_data_buffer_parse ( state ,
& buf ,
state - > data ,
state - > num_data ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
if ( buf . tag ! = IO_REPARSE_TAG_SYMLINK ) {
2011-06-30 17:06:46 +04:00
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
if ( psubstitute_name ! = NULL ) {
2023-07-07 12:40:19 +03:00
* psubstitute_name =
talloc_move ( mem_ctx , & buf . parsed . lnk . substitute_name ) ;
2011-06-30 17:06:46 +04:00
}
if ( pprint_name ! = NULL ) {
2023-07-07 12:40:19 +03:00
* pprint_name =
talloc_move ( mem_ctx , & buf . parsed . lnk . print_name ) ;
2011-06-30 17:06:46 +04:00
}
if ( pflags ! = NULL ) {
2023-07-07 12:40:19 +03:00
* pflags = buf . parsed . lnk . flags ;
2011-06-30 17:06:46 +04:00
}
2021-10-24 16:24:42 +03:00
2023-07-07 12:40:19 +03:00
tevent_req_received ( req ) ;
2021-10-24 16:24:42 +03:00
2011-06-30 17:06:46 +04:00
return NT_STATUS_OK ;
}
NTSTATUS cli_readlink ( struct cli_state * cli , const char * fname ,
TALLOC_CTX * mem_ctx , char * * psubstitute_name ,
char * * pprint_name , uint32_t * pflags )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2013-02-18 12:59:58 +04:00
struct tevent_context * ev ;
2011-06-30 17:06:46 +04:00
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
2012-05-26 13:45:09 +04:00
if ( smbXcli_conn_has_async_calls ( cli - > conn ) ) {
2011-06-30 17:06:46 +04:00
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
2013-02-18 12:08:19 +04:00
ev = samba_tevent_context_init ( frame ) ;
2011-06-30 17:06:46 +04:00
if ( ev = = NULL ) {
goto fail ;
}
req = cli_readlink_send ( frame , ev , cli , fname ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = cli_readlink_recv ( req , mem_ctx , psubstitute_name ,
pprint_name , pflags ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}