2008-05-17 03:52:47 +04:00
/*
Unix SMB / CIFS implementation .
helper functions for NAMED PIPE servers
Copyright ( C ) Stefan ( metze ) Metzmacher 2008
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"
2009-01-03 17:24:31 +03:00
# include <tevent.h>
2008-05-17 03:52:47 +04:00
# include "smbd/service.h"
# include "param/param.h"
2010-04-13 06:00:06 +04:00
# include "auth/auth.h"
2008-05-17 03:52:47 +04:00
# include "auth/session.h"
2009-01-21 12:43:15 +03:00
# include "auth/auth_sam_reply.h"
2010-02-04 19:03:04 +03:00
# include "lib/socket/socket.h"
# include "lib/tsocket/tsocket.h"
# include "libcli/util/tstream.h"
2008-05-17 03:52:47 +04:00
# include "librpc/gen_ndr/ndr_named_pipe_auth.h"
# include "system/passwd.h"
2010-02-04 19:03:04 +03:00
# include "system/network.h"
2009-04-21 06:55:42 +04:00
# include "libcli/raw/smb.h"
2009-09-17 20:41:00 +04:00
# include "auth/credentials/credentials.h"
# include "auth/credentials/credentials_krb5.h"
2010-04-19 09:51:57 +04:00
# include "libcli/security/dom_sid.h"
2008-05-17 03:52:47 +04:00
struct named_pipe_socket {
const char * pipe_name ;
const char * pipe_path ;
const struct stream_server_ops * ops ;
void * private_data ;
} ;
struct named_pipe_connection {
struct stream_connection * connection ;
const struct named_pipe_socket * pipe_sock ;
2010-02-04 19:03:04 +03:00
struct tstream_context * tstream ;
2008-05-17 03:52:47 +04:00
} ;
2010-02-04 19:03:04 +03:00
static void named_pipe_terminate_connection ( struct named_pipe_connection * pipe_conn , const char * reason )
2010-02-04 19:03:04 +03:00
{
2010-02-04 19:03:04 +03:00
stream_terminate_connection ( pipe_conn - > connection , reason ) ;
}
static NTSTATUS named_pipe_full_request ( void * private_data , DATA_BLOB blob , size_t * size )
{
if ( blob . length < 8 ) {
return STATUS_MORE_ENTRIES ;
}
if ( memcmp ( NAMED_PIPE_AUTH_MAGIC , & blob . data [ 4 ] , 4 ) ! = 0 ) {
DEBUG ( 0 , ( " named_pipe_full_request: wrong protocol \n " ) ) ;
* size = blob . length ;
/* the error will be handled in named_pipe_recv_auth_request */
return NT_STATUS_OK ;
}
* size = 4 + RIVAL ( blob . data , 0 ) ;
if ( * size > blob . length ) {
return STATUS_MORE_ENTRIES ;
}
2008-05-17 03:52:47 +04:00
2010-02-04 19:03:04 +03:00
return NT_STATUS_OK ;
}
2008-05-17 03:52:47 +04:00
2010-02-04 19:03:04 +03:00
static void named_pipe_auth_request ( struct tevent_req * subreq ) ;
2009-09-17 20:41:00 +04:00
2010-02-04 19:03:04 +03:00
static void named_pipe_accept ( struct stream_connection * conn )
{
struct named_pipe_socket * pipe_sock = talloc_get_type ( conn - > private_data ,
struct named_pipe_socket ) ;
struct named_pipe_connection * pipe_conn ;
struct tevent_req * subreq ;
int rc , fd ;
pipe_conn = talloc_zero ( conn , struct named_pipe_connection ) ;
if ( pipe_conn = = NULL ) {
stream_terminate_connection ( conn ,
" named_pipe_accept: out of memory " ) ;
2008-05-17 03:52:47 +04:00
return ;
}
2010-02-04 19:03:04 +03:00
TALLOC_FREE ( conn - > event . fde ) ;
2010-02-25 00:35:35 +03:00
/*
2010-02-04 19:03:04 +03:00
* We have to duplicate the fd , cause it gets closed when the tstream
* is freed and you shouldn ' t work a fd the tstream is based on .
2010-02-25 00:35:35 +03:00
*/
2010-02-04 19:03:04 +03:00
fd = dup ( socket_get_fd ( conn - > socket ) ) ;
if ( fd = = - 1 ) {
char * reason ;
reason = talloc_asprintf ( conn ,
" named_pipe_accept: failed to duplicate the file descriptor - %s " ,
strerror ( errno ) ) ;
if ( reason = = NULL ) {
reason = strerror ( errno ) ;
}
stream_terminate_connection ( conn , reason ) ;
}
rc = tstream_bsd_existing_socket ( pipe_conn ,
fd ,
& pipe_conn - > tstream ) ;
if ( rc < 0 ) {
stream_terminate_connection ( conn ,
" named_pipe_accept: out of memory " ) ;
return ;
}
2010-02-04 19:03:04 +03:00
2010-02-04 19:03:04 +03:00
pipe_conn - > connection = conn ;
pipe_conn - > pipe_sock = pipe_sock ;
conn - > private_data = pipe_conn ;
2008-05-17 03:52:47 +04:00
/*
2010-02-04 19:03:04 +03:00
* The named pipe pdu ' s have the length as 8 byte ( initial_read_size ) ,
* named_pipe_full_request provides the pdu length then .
2008-05-17 03:52:47 +04:00
*/
2010-02-04 19:03:04 +03:00
subreq = tstream_read_pdu_blob_send ( pipe_conn ,
pipe_conn - > connection - > event . ctx ,
pipe_conn - > tstream ,
8 , /* initial_read_size */
named_pipe_full_request ,
pipe_conn ) ;
if ( subreq = = NULL ) {
named_pipe_terminate_connection ( pipe_conn ,
" named_pipe_accept: "
" no memory for tstream_read_pdu_blob_send " ) ;
return ;
}
tevent_req_set_callback ( subreq , named_pipe_auth_request , pipe_conn ) ;
2010-02-25 00:35:35 +03:00
}
2010-02-04 19:03:04 +03:00
2010-02-04 19:03:04 +03:00
struct named_pipe_call {
struct named_pipe_connection * pipe_conn ;
DATA_BLOB in ;
DATA_BLOB out ;
struct iovec out_iov [ 1 ] ;
NTSTATUS status ;
} ;
static void named_pipe_handover_connection ( struct tevent_req * subreq ) ;
static void named_pipe_auth_request ( struct tevent_req * subreq )
2008-05-17 03:52:47 +04:00
{
2010-02-04 19:03:04 +03:00
struct named_pipe_connection * pipe_conn = tevent_req_callback_data ( subreq ,
struct named_pipe_connection ) ;
2008-05-17 03:52:47 +04:00
struct stream_connection * conn = pipe_conn - > connection ;
2010-02-04 19:03:04 +03:00
struct named_pipe_call * call ;
2008-05-17 03:52:47 +04:00
enum ndr_err_code ndr_err ;
union netr_Validation val ;
struct auth_serversupplied_info * server_info ;
2010-02-04 19:03:04 +03:00
struct named_pipe_auth_req pipe_request ;
struct named_pipe_auth_rep pipe_reply ;
2010-04-13 06:00:06 +04:00
struct auth_context * auth_context ;
2010-04-19 09:51:57 +04:00
uint32_t session_flags = 0 ;
struct dom_sid * anonymous_sid ;
2008-05-17 03:52:47 +04:00
NTSTATUS status ;
2010-04-26 15:56:06 +04:00
int ret ;
2008-05-17 03:52:47 +04:00
2010-02-04 19:03:04 +03:00
call = talloc ( pipe_conn , struct named_pipe_call ) ;
if ( call = = NULL ) {
named_pipe_terminate_connection ( pipe_conn ,
" named_pipe_auth_request: "
" no memory for named_pipe_call " ) ;
return ;
}
call - > pipe_conn = pipe_conn ;
status = tstream_read_pdu_blob_recv ( subreq ,
call ,
& call - > in ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
const char * reason ;
reason = talloc_asprintf ( call , " named_pipe_call_loop: "
" tstream_read_pdu_blob_recv() - %s " ,
nt_errstr ( status ) ) ;
if ( reason = = NULL ) {
reason = nt_errstr ( status ) ;
}
named_pipe_terminate_connection ( pipe_conn , reason ) ;
return ;
}
DEBUG ( 10 , ( " Received named_pipe packet of length %lu from %s \n " ,
( long ) call - > in . length ,
tsocket_address_string ( pipe_conn - > connection - > remote_address , call ) ) ) ;
dump_data ( 11 , call - > in . data , call - > in . length ) ;
2008-05-17 03:52:47 +04:00
/*
* TODO : check it ' s a root ( uid = = 0 ) pipe
*/
2010-02-04 19:03:04 +03:00
ZERO_STRUCT ( pipe_reply ) ;
pipe_reply . level = 0 ;
pipe_reply . status = NT_STATUS_INTERNAL_ERROR ;
2008-05-17 03:52:47 +04:00
/* parse the passed credentials */
ndr_err = ndr_pull_struct_blob_all (
2010-02-04 19:03:04 +03:00
& call - > in ,
2008-05-17 03:52:47 +04:00
pipe_conn ,
2010-02-04 19:03:04 +03:00
& pipe_request ,
( ndr_pull_flags_fn_t ) ndr_pull_named_pipe_auth_req ) ;
2008-05-17 03:52:47 +04:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2010-02-04 19:03:04 +03:00
pipe_reply . status = ndr_map_error2ntstatus ( ndr_err ) ;
2008-05-17 03:52:47 +04:00
DEBUG ( 2 , ( " Could not unmarshall named_pipe_auth_req: %s \n " ,
2010-02-04 19:03:04 +03:00
nt_errstr ( pipe_reply . status ) ) ) ;
2008-05-17 03:52:47 +04:00
goto reply ;
}
2009-04-21 06:55:42 +04:00
if ( DEBUGLVL ( 10 ) ) {
2010-02-04 19:03:04 +03:00
NDR_PRINT_DEBUG ( named_pipe_auth_req , & pipe_request ) ;
2009-04-21 06:55:42 +04:00
}
2010-02-04 19:03:04 +03:00
if ( strcmp ( NAMED_PIPE_AUTH_MAGIC , pipe_request . magic ) ! = 0 ) {
2008-05-17 03:52:47 +04:00
DEBUG ( 2 , ( " named_pipe_auth_req: invalid magic '%s' != %s \n " ,
2010-02-04 19:03:04 +03:00
pipe_request . magic , NAMED_PIPE_AUTH_MAGIC ) ) ;
pipe_reply . status = NT_STATUS_INVALID_PARAMETER ;
2008-05-17 03:52:47 +04:00
goto reply ;
}
2010-02-04 19:03:04 +03:00
switch ( pipe_request . level ) {
2008-05-17 03:52:47 +04:00
case 0 :
/*
* anon connection , we don ' t create a session info
* and leave it NULL
*/
2010-02-04 19:03:04 +03:00
pipe_reply . level = 0 ;
pipe_reply . status = NT_STATUS_OK ;
2008-05-17 03:52:47 +04:00
break ;
case 1 :
2010-02-04 19:03:04 +03:00
val . sam3 = & pipe_request . info . info1 ;
pipe_reply . level = 1 ;
pipe_reply . status = make_server_info_netlogon_validation ( pipe_conn ,
" TODO " ,
3 , & val ,
& server_info ) ;
if ( ! NT_STATUS_IS_OK ( pipe_reply . status ) ) {
2008-05-17 03:52:47 +04:00
DEBUG ( 2 , ( " make_server_info_netlogon_validation returned "
2010-02-04 19:03:04 +03:00
" %s \n " , nt_errstr ( pipe_reply . status ) ) ) ;
2008-05-17 03:52:47 +04:00
goto reply ;
}
2010-04-13 06:00:06 +04:00
pipe_reply . status = auth_context_create ( conn ,
conn - > event . ctx , conn - > msg_ctx ,
conn - > lp_ctx ,
& auth_context ) ;
if ( ! NT_STATUS_IS_OK ( pipe_reply . status ) ) {
DEBUG ( 2 , ( " auth_context_create returned "
" %s \n " , nt_errstr ( pipe_reply . status ) ) ) ;
goto reply ;
}
2010-04-19 09:51:57 +04:00
anonymous_sid = dom_sid_parse_talloc ( auth_context , SID_NT_ANONYMOUS ) ;
if ( anonymous_sid = = NULL ) {
named_pipe_terminate_connection ( pipe_conn , " Failed to parse Anonymous SID " ) ;
talloc_free ( auth_context ) ;
return ;
}
session_flags = AUTH_SESSION_INFO_DEFAULT_GROUPS ;
if ( ! dom_sid_equal ( anonymous_sid , server_info - > account_sid ) ) {
session_flags | = AUTH_SESSION_INFO_AUTHENTICATED ;
}
2010-04-13 06:00:06 +04:00
2008-05-17 03:52:47 +04:00
/* setup the session_info on the connection */
2010-04-13 06:00:06 +04:00
pipe_reply . status = auth_context - > generate_session_info ( conn ,
auth_context ,
server_info ,
2010-04-19 09:51:57 +04:00
session_flags ,
2010-04-13 06:00:06 +04:00
& conn - > session_info ) ;
talloc_free ( auth_context ) ;
2010-02-04 19:03:04 +03:00
if ( ! NT_STATUS_IS_OK ( pipe_reply . status ) ) {
2008-05-17 03:52:47 +04:00
DEBUG ( 2 , ( " auth_generate_session_info failed: %s \n " ,
2010-02-04 19:03:04 +03:00
nt_errstr ( pipe_reply . status ) ) ) ;
2008-05-17 03:52:47 +04:00
goto reply ;
}
2009-04-21 06:55:42 +04:00
break ;
case 2 :
2010-02-04 19:03:04 +03:00
pipe_reply . level = 2 ;
pipe_reply . info . info2 . file_type = FILE_TYPE_MESSAGE_MODE_PIPE ;
pipe_reply . info . info2 . device_state = 0xff | 0x0400 | 0x0100 ;
pipe_reply . info . info2 . allocation_size = 4096 ;
2009-04-21 06:55:42 +04:00
2010-02-04 19:03:04 +03:00
if ( pipe_request . info . info2 . sam_info3 = = NULL ) {
2009-04-21 06:55:42 +04:00
/*
* anon connection , we don ' t create a session info
* and leave it NULL
*/
2010-02-04 19:03:04 +03:00
pipe_reply . status = NT_STATUS_OK ;
2009-04-21 06:55:42 +04:00
break ;
}
2010-02-04 19:03:04 +03:00
val . sam3 = pipe_request . info . info2 . sam_info3 ;
2009-04-21 06:55:42 +04:00
2010-02-04 19:03:04 +03:00
pipe_reply . status = make_server_info_netlogon_validation ( pipe_conn ,
2009-04-21 06:55:42 +04:00
val . sam3 - > base . account_name . string ,
3 , & val , & server_info ) ;
2010-02-04 19:03:04 +03:00
if ( ! NT_STATUS_IS_OK ( pipe_reply . status ) ) {
2009-04-21 06:55:42 +04:00
DEBUG ( 2 , ( " make_server_info_netlogon_validation returned "
2010-02-04 19:03:04 +03:00
" %s \n " , nt_errstr ( pipe_reply . status ) ) ) ;
2009-04-21 06:55:42 +04:00
goto reply ;
}
/* setup the session_info on the connection */
2010-04-13 06:00:06 +04:00
pipe_reply . status = auth_context_create ( conn ,
conn - > event . ctx , conn - > msg_ctx ,
2009-04-21 06:55:42 +04:00
conn - > lp_ctx ,
2010-04-13 06:00:06 +04:00
& auth_context ) ;
if ( ! NT_STATUS_IS_OK ( pipe_reply . status ) ) {
DEBUG ( 2 , ( " auth_context_create returned "
" %s \n " , nt_errstr ( pipe_reply . status ) ) ) ;
goto reply ;
}
2010-04-19 09:51:57 +04:00
anonymous_sid = dom_sid_parse_talloc ( auth_context , SID_NT_ANONYMOUS ) ;
if ( anonymous_sid = = NULL ) {
named_pipe_terminate_connection ( pipe_conn , " Failed to parse Anonymous SID " ) ;
talloc_free ( auth_context ) ;
return ;
}
session_flags = AUTH_SESSION_INFO_DEFAULT_GROUPS ;
if ( ! dom_sid_equal ( anonymous_sid , server_info - > account_sid ) ) {
session_flags | = AUTH_SESSION_INFO_AUTHENTICATED ;
}
2010-04-13 06:00:06 +04:00
pipe_reply . status = auth_context - > generate_session_info ( conn ,
auth_context ,
server_info ,
2010-04-19 09:51:57 +04:00
session_flags ,
2010-04-13 06:00:06 +04:00
& conn - > session_info ) ;
talloc_free ( auth_context ) ;
2010-02-04 19:03:04 +03:00
if ( ! NT_STATUS_IS_OK ( pipe_reply . status ) ) {
2009-04-21 06:55:42 +04:00
DEBUG ( 2 , ( " auth_generate_session_info failed: %s \n " ,
2010-02-04 19:03:04 +03:00
nt_errstr ( pipe_reply . status ) ) ) ;
2009-04-21 06:55:42 +04:00
goto reply ;
}
2010-02-04 19:03:04 +03:00
conn - > session_info - > session_key = data_blob_const ( pipe_request . info . info2 . session_key ,
pipe_request . info . info2 . session_key_length ) ;
talloc_steal ( conn - > session_info , pipe_request . info . info2 . session_key ) ;
2009-04-21 06:55:42 +04:00
2009-09-17 20:41:00 +04:00
break ;
case 3 :
2010-02-04 19:03:04 +03:00
pipe_reply . level = 3 ;
pipe_reply . info . info3 . file_type = FILE_TYPE_MESSAGE_MODE_PIPE ;
pipe_reply . info . info3 . device_state = 0xff | 0x0400 | 0x0100 ;
pipe_reply . info . info3 . allocation_size = 4096 ;
2009-09-17 20:41:00 +04:00
2010-04-26 15:56:06 +04:00
if ( pipe_request . info . info3 . server_addr = = NULL ) {
pipe_reply . status = NT_STATUS_INVALID_ADDRESS ;
DEBUG ( 2 , ( " Missing server address \n " ) ) ;
goto reply ;
}
if ( pipe_request . info . info3 . client_addr = = NULL ) {
pipe_reply . status = NT_STATUS_INVALID_ADDRESS ;
DEBUG ( 2 , ( " Missing client address \n " ) ) ;
goto reply ;
}
ret = tsocket_address_inet_from_strings ( conn , " ip " ,
pipe_request . info . info3 . server_addr ,
pipe_request . info . info3 . server_port ,
& conn - > local_address ) ;
if ( ret ! = 0 ) {
DEBUG ( 2 , ( " Invalid server address[%s] port[%u] - %s \n " ,
pipe_request . info . info3 . server_addr ,
pipe_request . info . info3 . server_port ,
strerror ( errno ) ) ) ;
pipe_reply . status = NT_STATUS_INVALID_ADDRESS ;
goto reply ;
}
ret = tsocket_address_inet_from_strings ( conn , " ip " ,
pipe_request . info . info3 . client_addr ,
pipe_request . info . info3 . client_port ,
& conn - > remote_address ) ;
if ( ret ! = 0 ) {
DEBUG ( 2 , ( " Invalid client address[%s] port[%u] - %s \n " ,
pipe_request . info . info3 . client_addr ,
pipe_request . info . info3 . client_port ,
strerror ( errno ) ) ) ;
pipe_reply . status = NT_STATUS_INVALID_ADDRESS ;
goto reply ;
}
2010-02-04 19:03:04 +03:00
if ( pipe_request . info . info3 . sam_info3 = = NULL ) {
2009-09-17 20:41:00 +04:00
/*
* anon connection , we don ' t create a session info
* and leave it NULL
*/
2010-02-04 19:03:04 +03:00
pipe_reply . status = NT_STATUS_OK ;
2009-09-17 20:41:00 +04:00
break ;
}
2010-02-04 19:03:04 +03:00
val . sam3 = pipe_request . info . info3 . sam_info3 ;
2009-09-17 20:41:00 +04:00
2010-02-04 19:03:04 +03:00
pipe_reply . status = make_server_info_netlogon_validation ( pipe_conn ,
2009-09-17 20:41:00 +04:00
val . sam3 - > base . account_name . string ,
3 , & val , & server_info ) ;
2010-02-04 19:03:04 +03:00
if ( ! NT_STATUS_IS_OK ( pipe_reply . status ) ) {
2009-09-17 20:41:00 +04:00
DEBUG ( 2 , ( " make_server_info_netlogon_validation returned "
2010-02-04 19:03:04 +03:00
" %s \n " , nt_errstr ( pipe_reply . status ) ) ) ;
2009-09-17 20:41:00 +04:00
goto reply ;
}
/* setup the session_info on the connection */
2010-04-13 06:00:06 +04:00
pipe_reply . status = auth_context_create ( conn ,
conn - > event . ctx , conn - > msg_ctx ,
conn - > lp_ctx ,
& auth_context ) ;
if ( ! NT_STATUS_IS_OK ( pipe_reply . status ) ) {
DEBUG ( 2 , ( " auth_context_create returned "
" %s \n " , nt_errstr ( pipe_reply . status ) ) ) ;
goto reply ;
}
2010-04-19 09:51:57 +04:00
anonymous_sid = dom_sid_parse_talloc ( auth_context , SID_NT_ANONYMOUS ) ;
if ( anonymous_sid = = NULL ) {
named_pipe_terminate_connection ( pipe_conn , " Failed to parse Anonymous SID " ) ;
talloc_free ( auth_context ) ;
return ;
}
session_flags = AUTH_SESSION_INFO_DEFAULT_GROUPS ;
if ( ! dom_sid_equal ( anonymous_sid , server_info - > account_sid ) ) {
session_flags | = AUTH_SESSION_INFO_AUTHENTICATED ;
}
2010-04-13 06:00:06 +04:00
/* setup the session_info on the connection */
pipe_reply . status = auth_context - > generate_session_info ( conn ,
auth_context ,
server_info ,
2010-04-19 09:51:57 +04:00
session_flags ,
2010-04-13 06:00:06 +04:00
& conn - > session_info ) ;
talloc_free ( auth_context ) ;
2010-02-04 19:03:04 +03:00
if ( ! NT_STATUS_IS_OK ( pipe_reply . status ) ) {
2009-09-17 20:41:00 +04:00
DEBUG ( 2 , ( " auth_generate_session_info failed: %s \n " ,
2010-02-04 19:03:04 +03:00
nt_errstr ( pipe_reply . status ) ) ) ;
2009-09-17 20:41:00 +04:00
goto reply ;
}
2010-02-04 19:03:04 +03:00
if ( pipe_request . info . info3 . gssapi_delegated_creds_length ) {
2009-09-17 20:41:00 +04:00
OM_uint32 minor_status ;
gss_buffer_desc cred_token ;
gss_cred_id_t cred_handle ;
2010-02-25 08:16:33 +03:00
const char * error_string ;
2009-09-17 20:41:00 +04:00
DEBUG ( 10 , ( " named_pipe_auth: delegated credentials supplied by client \n " ) ) ;
2010-02-04 19:03:04 +03:00
cred_token . value = pipe_request . info . info3 . gssapi_delegated_creds ;
cred_token . length = pipe_request . info . info3 . gssapi_delegated_creds_length ;
2009-09-17 20:41:00 +04:00
ret = gss_import_cred ( & minor_status ,
& cred_token ,
& cred_handle ) ;
if ( ret ! = GSS_S_COMPLETE ) {
2010-02-04 19:03:04 +03:00
pipe_reply . status = NT_STATUS_INTERNAL_ERROR ;
2009-09-17 20:41:00 +04:00
goto reply ;
}
conn - > session_info - > credentials = cli_credentials_init ( conn - > session_info ) ;
2010-02-04 19:03:04 +03:00
if ( conn - > session_info - > credentials = = NULL ) {
pipe_reply . status = NT_STATUS_NO_MEMORY ;
2009-09-17 20:41:00 +04:00
goto reply ;
}
cli_credentials_set_conf ( conn - > session_info - > credentials ,
conn - > lp_ctx ) ;
/* Just so we don't segfault trying to get at a username */
cli_credentials_set_anonymous ( conn - > session_info - > credentials ) ;
ret = cli_credentials_set_client_gss_creds ( conn - > session_info - > credentials ,
conn - > event . ctx ,
conn - > lp_ctx ,
cred_handle ,
2010-02-25 08:16:33 +03:00
CRED_SPECIFIED , & error_string ) ;
2009-09-17 20:41:00 +04:00
if ( ret ) {
2010-02-04 19:03:04 +03:00
pipe_reply . status = NT_STATUS_INTERNAL_ERROR ;
2010-02-25 08:16:33 +03:00
DEBUG ( 2 , ( " Failed to set pipe forwarded creds: %s \n " , error_string ) ) ;
2009-09-17 20:41:00 +04:00
goto reply ;
}
/* This credential handle isn't useful for password authentication, so ensure nobody tries to do that */
cli_credentials_set_kerberos_state ( conn - > session_info - > credentials ,
CRED_MUST_USE_KERBEROS ) ;
}
2010-02-04 19:03:04 +03:00
conn - > session_info - > session_key = data_blob_const ( pipe_request . info . info3 . session_key ,
pipe_request . info . info3 . session_key_length ) ;
talloc_steal ( conn - > session_info , pipe_request . info . info3 . session_key ) ;
2009-09-17 20:41:00 +04:00
2008-05-17 03:52:47 +04:00
break ;
default :
2010-02-04 19:03:04 +03:00
DEBUG ( 0 , ( " named_pipe_auth_req: unknown level %u \n " ,
pipe_request . level ) ) ;
pipe_reply . level = 0 ;
pipe_reply . status = NT_STATUS_INVALID_LEVEL ;
2008-05-17 03:52:47 +04:00
goto reply ;
}
reply :
/* create the output */
2010-02-04 19:03:04 +03:00
ndr_err = ndr_push_struct_blob ( & call - > out , pipe_conn ,
& pipe_reply ,
2008-05-17 03:52:47 +04:00
( ndr_push_flags_fn_t ) ndr_push_named_pipe_auth_rep ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2010-02-04 19:03:04 +03:00
const char * reason ;
2008-05-17 03:52:47 +04:00
status = ndr_map_error2ntstatus ( ndr_err ) ;
2010-02-04 19:03:04 +03:00
reason = talloc_asprintf ( pipe_conn , " named_pipe_auth_request: could not marshall named_pipe_auth_rep: %s \n " ,
nt_errstr ( status ) ) ;
if ( reason = = NULL ) {
reason = " named_pipe_auth_request: could not marshall named_pipe_auth_rep " ;
}
named_pipe_terminate_connection ( pipe_conn , reason ) ;
return ;
2008-05-17 03:52:47 +04:00
}
2010-02-04 19:03:04 +03:00
DEBUG ( 10 , ( " named_pipe_auth_request: named_pipe_auth reply[%u] \n " ,
( unsigned ) call - > out . length ) ) ;
dump_data ( 11 , call - > out . data , call - > out . length ) ;
2009-04-21 06:55:42 +04:00
if ( DEBUGLVL ( 10 ) ) {
2010-02-04 19:03:04 +03:00
NDR_PRINT_DEBUG ( named_pipe_auth_rep , & pipe_reply ) ;
2009-04-21 06:55:42 +04:00
}
2010-02-04 19:03:04 +03:00
call - > status = pipe_reply . status ;
call - > out_iov [ 0 ] . iov_base = call - > out . data ;
call - > out_iov [ 0 ] . iov_len = call - > out . length ;
subreq = tstream_writev_send ( call ,
pipe_conn - > connection - > event . ctx ,
pipe_conn - > tstream ,
call - > out_iov , 1 ) ;
if ( subreq = = NULL ) {
named_pipe_terminate_connection ( pipe_conn , " named_pipe_auth_request: "
" no memory for tstream_writev_send " ) ;
return ;
2010-02-04 19:03:04 +03:00
}
2010-02-04 19:03:04 +03:00
tevent_req_set_callback ( subreq , named_pipe_handover_connection , call ) ;
2008-05-17 03:52:47 +04:00
}
2010-02-04 19:03:04 +03:00
static void named_pipe_handover_connection ( struct tevent_req * subreq )
2008-05-17 03:52:47 +04:00
{
2010-02-04 19:03:04 +03:00
struct named_pipe_call * call = tevent_req_callback_data ( subreq ,
struct named_pipe_call ) ;
struct named_pipe_connection * pipe_conn = call - > pipe_conn ;
struct stream_connection * conn = pipe_conn - > connection ;
int sys_errno ;
int rc ;
rc = tstream_writev_recv ( subreq , & sys_errno ) ;
TALLOC_FREE ( subreq ) ;
if ( rc = = - 1 ) {
const char * reason ;
reason = talloc_asprintf ( call , " named_pipe_handover_connection: "
" tstream_writev_recv() - %d:%s " ,
sys_errno , strerror ( sys_errno ) ) ;
if ( reason = = NULL ) {
reason = " named_pipe_handover_connection: "
" tstream_writev_recv() failed " ;
}
2008-05-17 03:52:47 +04:00
2010-02-04 19:03:04 +03:00
named_pipe_terminate_connection ( pipe_conn , reason ) ;
return ;
}
2010-02-25 00:35:35 +03:00
2010-02-04 19:03:04 +03:00
if ( ! NT_STATUS_IS_OK ( call - > status ) ) {
const char * reason ;
reason = talloc_asprintf ( call , " named_pipe_handover_connection: "
" reply status - %s " , nt_errstr ( call - > status ) ) ;
if ( reason = = NULL ) {
reason = nt_errstr ( call - > status ) ;
}
named_pipe_terminate_connection ( pipe_conn , reason ) ;
return ;
}
/*
* remove the named_pipe layer together with its packet layer
*/
conn - > ops = pipe_conn - > pipe_sock - > ops ;
conn - > private_data = pipe_conn - > pipe_sock - > private_data ;
talloc_unlink ( conn , pipe_conn ) ;
conn - > event . fde = tevent_add_fd ( conn - > event . ctx ,
conn ,
socket_get_fd ( conn - > socket ) ,
TEVENT_FD_READ ,
stream_io_handler_fde ,
conn ) ;
if ( conn - > event . fde = = NULL ) {
named_pipe_terminate_connection ( pipe_conn , " named_pipe_handover_connection: "
" setting up the stream_io_handler_fde failed " ) ;
return ;
}
/*
* hand over to the real pipe implementation ,
* now that we have setup the transport session_info
*/
conn - > ops - > accept_connection ( conn ) ;
DEBUG ( 10 , ( " named_pipe_handover_connection[%s]: succeeded \n " ,
conn - > ops - > name ) ) ;
/* we don't have to free call here as the connection got closed */
2008-05-17 03:52:47 +04:00
}
/*
2010-02-04 19:03:04 +03:00
called when a pipe socket becomes readable
2008-05-17 03:52:47 +04:00
*/
2010-02-04 19:03:04 +03:00
static void named_pipe_recv ( struct stream_connection * conn , uint16_t flags )
2008-05-17 03:52:47 +04:00
{
struct named_pipe_connection * pipe_conn = talloc_get_type (
2010-02-04 19:03:04 +03:00
conn - > private_data , struct named_pipe_connection ) ;
2008-05-17 03:52:47 +04:00
2010-02-04 19:03:04 +03:00
named_pipe_terminate_connection ( pipe_conn ,
" named_pipe_recv: called " ) ;
2010-02-25 00:35:35 +03:00
}
/*
2010-02-04 19:03:04 +03:00
called when a pipe socket becomes writable
2010-02-25 00:35:35 +03:00
*/
2010-02-04 19:03:04 +03:00
static void named_pipe_send ( struct stream_connection * conn , uint16_t flags )
2010-02-25 00:35:35 +03:00
{
struct named_pipe_connection * pipe_conn = talloc_get_type (
2010-02-04 19:03:04 +03:00
conn - > private_data , struct named_pipe_connection ) ;
2010-02-25 00:35:35 +03:00
2010-02-04 19:03:04 +03:00
named_pipe_terminate_connection ( pipe_conn ,
" named_pipe_send: called " ) ;
2008-05-17 03:52:47 +04:00
}
static const struct stream_server_ops named_pipe_stream_ops = {
. name = " named_pipe " ,
. accept_connection = named_pipe_accept ,
. recv_handler = named_pipe_recv ,
. send_handler = named_pipe_send ,
} ;
2008-12-29 22:24:57 +03:00
NTSTATUS stream_setup_named_pipe ( struct tevent_context * event_context ,
2008-05-17 03:52:47 +04:00
struct loadparm_context * lp_ctx ,
const struct model_ops * model_ops ,
const struct stream_server_ops * stream_ops ,
const char * pipe_name ,
void * private_data )
{
char * dirname ;
struct named_pipe_socket * pipe_sock ;
NTSTATUS status = NT_STATUS_NO_MEMORY ; ;
pipe_sock = talloc ( event_context , struct named_pipe_socket ) ;
if ( pipe_sock = = NULL ) {
goto fail ;
}
/* remember the details about the pipe */
pipe_sock - > pipe_name = talloc_strdup ( pipe_sock , pipe_name ) ;
if ( pipe_sock - > pipe_name = = NULL ) {
goto fail ;
}
dirname = talloc_asprintf ( pipe_sock , " %s/np " , lp_ncalrpc_dir ( lp_ctx ) ) ;
if ( dirname = = NULL ) {
goto fail ;
}
if ( ! directory_create_or_exist ( dirname , geteuid ( ) , 0700 ) ) {
status = map_nt_error_from_unix ( errno ) ;
2009-09-19 05:05:55 +04:00
DEBUG ( 0 , ( __location__ " : Failed to create stream pipe directory %s - %s \n " ,
dirname , nt_errstr ( status ) ) ) ;
2008-05-17 03:52:47 +04:00
goto fail ;
}
if ( strncmp ( pipe_name , " \\ pipe \\ " , 6 ) = = 0 ) {
pipe_name + = 6 ;
}
pipe_sock - > pipe_path = talloc_asprintf ( pipe_sock , " %s/%s " , dirname ,
pipe_name ) ;
if ( pipe_sock - > pipe_path = = NULL ) {
goto fail ;
}
talloc_free ( dirname ) ;
pipe_sock - > ops = stream_ops ;
pipe_sock - > private_data = talloc_reference ( pipe_sock , private_data ) ;
status = stream_setup_socket ( event_context ,
lp_ctx ,
model_ops ,
& named_pipe_stream_ops ,
" unix " ,
pipe_sock - > pipe_path ,
NULL ,
NULL ,
pipe_sock ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
return NT_STATUS_OK ;
fail :
talloc_free ( pipe_sock ) ;
return status ;
}