2005-09-22 22:35:08 +04:00
/*
Unix SMB / CIFS implementation .
Main winbindd samba3 server routines
Copyright ( C ) Stefan Metzmacher 2005
Copyright ( C ) Volker Lendecke 2005
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# include "smbd/service_stream.h"
# include "nsswitch/winbind_nss_config.h"
# include "nsswitch/winbindd_nss.h"
# include "winbind/wb_server.h"
# include "winbind/wb_samba3_protocol.h"
2005-09-26 01:01:56 +04:00
# include "winbind/wb_async_helpers.h"
# include "librpc/gen_ndr/nbt.h"
# include "libcli/raw/libcliraw.h"
# include "libcli/composite/composite.h"
2005-10-01 20:36:04 +04:00
# include "libcli/smb_composite/smb_composite.h"
2005-09-26 17:42:42 +04:00
# include "include/version.h"
2005-10-03 17:46:11 +04:00
# include "lib/events/events.h"
2005-10-09 16:13:05 +04:00
# include "librpc/gen_ndr/ndr_netlogon.h"
2005-09-22 22:35:08 +04:00
NTSTATUS wbsrv_samba3_interface_version ( struct wbsrv_samba3_call * s3call )
{
s3call - > response . result = WINBINDD_OK ;
s3call - > response . data . interface_version = WINBIND_INTERFACE_VERSION ;
return NT_STATUS_OK ;
}
2005-09-26 17:42:42 +04:00
NTSTATUS wbsrv_samba3_info ( struct wbsrv_samba3_call * s3call )
{
s3call - > response . result = WINBINDD_OK ;
s3call - > response . data . info . winbind_separator = * lp_winbind_separator ( ) ;
WBSRV_SAMBA3_SET_STRING ( s3call - > response . data . info . samba_version , SAMBA_VERSION_STRING ) ;
return NT_STATUS_OK ;
}
NTSTATUS wbsrv_samba3_domain_name ( struct wbsrv_samba3_call * s3call )
{
s3call - > response . result = WINBINDD_OK ;
WBSRV_SAMBA3_SET_STRING ( s3call - > response . data . domain_name , lp_workgroup ( ) ) ;
return NT_STATUS_OK ;
}
NTSTATUS wbsrv_samba3_netbios_name ( struct wbsrv_samba3_call * s3call )
{
s3call - > response . result = WINBINDD_OK ;
WBSRV_SAMBA3_SET_STRING ( s3call - > response . data . netbios_name , lp_netbios_name ( ) ) ;
return NT_STATUS_OK ;
}
2005-09-22 22:35:08 +04:00
NTSTATUS wbsrv_samba3_priv_pipe_dir ( struct wbsrv_samba3_call * s3call )
{
s3call - > response . result = WINBINDD_OK ;
s3call - > response . extra_data = smbd_tmp_path ( s3call ,
WINBINDD_SAMBA3_PRIVILEGED_SOCKET ) ;
NT_STATUS_HAVE_NO_MEMORY ( s3call - > response . extra_data ) ;
return NT_STATUS_OK ;
}
NTSTATUS wbsrv_samba3_ping ( struct wbsrv_samba3_call * s3call )
{
s3call - > response . result = WINBINDD_OK ;
return NT_STATUS_OK ;
}
2005-09-26 01:01:56 +04:00
2005-10-08 20:25:00 +04:00
static void checkmachacc_recv_creds ( struct composite_context * ctx ) ;
2005-10-03 17:46:11 +04:00
NTSTATUS wbsrv_samba3_check_machacc ( struct wbsrv_samba3_call * s3call )
2005-09-26 01:01:56 +04:00
{
2005-10-01 20:36:04 +04:00
struct composite_context * ctx ;
2005-10-08 20:25:00 +04:00
DEBUG ( 5 , ( " wbsrv_samba3_check_machacc called \n " ) ) ;
2005-10-01 20:36:04 +04:00
r10852: Continuation-based programming can become a bit spaghetti...
Initialize a domain structure properly. Excerpt from wb_init_domain.c:
/*
* Initialize a domain:
*
* - With schannel credentials, try to open the SMB connection with the machine
* creds. Fall back to anonymous.
*
* - If we have schannel creds, do the auth2 and open the schannel'ed netlogon
* pipe.
*
* - Open LSA. If we have machine creds, try to open with ntlmssp. Fall back
* to schannel and then to anon bind.
*
* - With queryinfopolicy, verify that we're talking to the right domain
*
* A bit complex, but with all the combinations I think it's the best we can
* get. NT4, W2k3SP1 and W2k all have different combinations, but in the end we
* have a signed&sealed lsa connection on all of them.
*
* Is this overkill? In particular the authenticated SMB connection seems a
* bit overkill, given that we do schannel for netlogon and ntlmssp for
* lsa later on w2k3, the others don't do this anyway.
*/
Thanks to Jeremy for his detective work, and to the Samba4 team for providing
such a great infrastructure.
Next step is to connect to SAM. Do it via LDAP if we can, fall back to samr
with all we have.
Volker
2005-10-10 00:32:24 +04:00
ctx = wb_cmd_checkmachacc_send ( s3call - > call ) ;
2005-10-08 20:25:00 +04:00
NT_STATUS_HAVE_NO_MEMORY ( ctx ) ;
2005-10-01 20:36:04 +04:00
2005-10-08 20:25:00 +04:00
ctx - > async . fn = checkmachacc_recv_creds ;
2005-10-01 20:36:04 +04:00
ctx - > async . private_data = s3call ;
2005-10-08 20:25:00 +04:00
s3call - > call - > flags | = WBSRV_CALL_FLAGS_REPLY_ASYNC ;
return NT_STATUS_OK ;
2005-09-26 01:01:56 +04:00
}
2005-10-03 17:46:11 +04:00
2005-10-08 20:25:00 +04:00
static void checkmachacc_recv_creds ( struct composite_context * ctx )
2005-10-03 17:46:11 +04:00
{
struct wbsrv_samba3_call * s3call =
2005-10-08 20:25:00 +04:00
talloc_get_type ( ctx - > async . private_data ,
2005-10-03 17:46:11 +04:00
struct wbsrv_samba3_call ) ;
NTSTATUS status ;
r10852: Continuation-based programming can become a bit spaghetti...
Initialize a domain structure properly. Excerpt from wb_init_domain.c:
/*
* Initialize a domain:
*
* - With schannel credentials, try to open the SMB connection with the machine
* creds. Fall back to anonymous.
*
* - If we have schannel creds, do the auth2 and open the schannel'ed netlogon
* pipe.
*
* - Open LSA. If we have machine creds, try to open with ntlmssp. Fall back
* to schannel and then to anon bind.
*
* - With queryinfopolicy, verify that we're talking to the right domain
*
* A bit complex, but with all the combinations I think it's the best we can
* get. NT4, W2k3SP1 and W2k all have different combinations, but in the end we
* have a signed&sealed lsa connection on all of them.
*
* Is this overkill? In particular the authenticated SMB connection seems a
* bit overkill, given that we do schannel for netlogon and ntlmssp for
* lsa later on w2k3, the others don't do this anyway.
*/
Thanks to Jeremy for his detective work, and to the Samba4 team for providing
such a great infrastructure.
Next step is to connect to SAM. Do it via LDAP if we can, fall back to samr
with all we have.
Volker
2005-10-10 00:32:24 +04:00
status = wb_cmd_checkmachacc_recv ( ctx ) ;
2005-10-08 20:25:00 +04:00
if ( NT_STATUS_IS_OK ( status ) ) {
s3call - > response . result = WINBINDD_OK ;
} else {
struct winbindd_response * resp = & s3call - > response ;
resp - > result = WINBINDD_ERROR ;
WBSRV_SAMBA3_SET_STRING ( resp - > data . auth . nt_status_string ,
2005-10-03 17:46:11 +04:00
nt_errstr ( status ) ) ;
2005-10-08 20:25:00 +04:00
WBSRV_SAMBA3_SET_STRING ( resp - > data . auth . error_string ,
2005-10-03 17:46:11 +04:00
nt_errstr ( status ) ) ;
2005-10-08 20:25:00 +04:00
resp - > data . auth . pam_error = nt_status_to_pam ( status ) ;
2005-10-03 17:46:11 +04:00
}
status = wbsrv_send_reply ( s3call - > call ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
wbsrv_terminate_connection ( s3call - > call - > wbconn ,
" wbsrv_queue_reply() failed " ) ;
return ;
}
2005-09-26 01:01:56 +04:00
}
2005-10-03 21:36:49 +04:00
2005-10-16 02:01:15 +04:00
static void getdcname_recv_dc ( struct composite_context * ctx ) ;
NTSTATUS wbsrv_samba3_getdcname ( struct wbsrv_samba3_call * s3call )
{
struct composite_context * ctx ;
DEBUG ( 5 , ( " wbsrv_samba3_getdcname called \n " ) ) ;
ctx = wb_cmd_getdcname_send ( s3call - > call ,
s3call - > request . domain_name ) ;
NT_STATUS_HAVE_NO_MEMORY ( ctx ) ;
ctx - > async . fn = getdcname_recv_dc ;
ctx - > async . private_data = s3call ;
s3call - > call - > flags | = WBSRV_CALL_FLAGS_REPLY_ASYNC ;
return NT_STATUS_OK ;
}
static void getdcname_recv_dc ( struct composite_context * ctx )
{
struct wbsrv_samba3_call * s3call =
talloc_get_type ( ctx - > async . private_data ,
struct wbsrv_samba3_call ) ;
const char * dcname ;
NTSTATUS status ;
status = wb_cmd_getdcname_recv ( ctx , s3call , & dcname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) goto done ;
s3call - > response . result = WINBINDD_OK ;
WBSRV_SAMBA3_SET_STRING ( s3call - > response . data . dc_name , dcname ) ;
2005-10-16 16:43:09 +04:00
done :
if ( ! NT_STATUS_IS_OK ( status ) ) {
struct winbindd_response * resp = & s3call - > response ;
resp - > result = WINBINDD_ERROR ;
WBSRV_SAMBA3_SET_STRING ( resp - > data . auth . nt_status_string ,
nt_errstr ( status ) ) ;
WBSRV_SAMBA3_SET_STRING ( resp - > data . auth . error_string ,
nt_errstr ( status ) ) ;
resp - > data . auth . pam_error = nt_status_to_pam ( status ) ;
}
status = wbsrv_send_reply ( s3call - > call ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
wbsrv_terminate_connection ( s3call - > call - > wbconn ,
" wbsrv_queue_reply() failed " ) ;
return ;
}
}
static void userdomgroups_recv_groups ( struct composite_context * ctx ) ;
NTSTATUS wbsrv_samba3_userdomgroups ( struct wbsrv_samba3_call * s3call )
{
struct composite_context * ctx ;
struct dom_sid * sid ;
DEBUG ( 5 , ( " wbsrv_samba3_userdomgroups called \n " ) ) ;
sid = dom_sid_parse_talloc ( s3call , s3call - > request . data . sid ) ;
if ( sid = = NULL ) {
DEBUG ( 5 , ( " Could not parse sid %s \n " ,
s3call - > request . data . sid ) ) ;
return NT_STATUS_NO_MEMORY ;
}
ctx = wb_cmd_userdomgroups_send ( s3call - > call , sid ) ;
NT_STATUS_HAVE_NO_MEMORY ( ctx ) ;
ctx - > async . fn = userdomgroups_recv_groups ;
ctx - > async . private_data = s3call ;
s3call - > call - > flags | = WBSRV_CALL_FLAGS_REPLY_ASYNC ;
return NT_STATUS_OK ;
}
static void userdomgroups_recv_groups ( struct composite_context * ctx )
{
struct wbsrv_samba3_call * s3call =
talloc_get_type ( ctx - > async . private_data ,
struct wbsrv_samba3_call ) ;
int i , num_sids ;
struct dom_sid * * sids ;
char * sids_string ;
NTSTATUS status ;
status = wb_cmd_userdomgroups_recv ( ctx , s3call , & num_sids , & sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) goto done ;
sids_string = talloc_strdup ( s3call , " " ) ;
if ( sids_string = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
for ( i = 0 ; i < num_sids ; i + + ) {
sids_string = talloc_asprintf_append (
sids_string , " %s \n " , dom_sid_string ( s3call , sids [ i ] ) ) ;
}
if ( sids_string = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto done ;
}
s3call - > response . result = WINBINDD_OK ;
s3call - > response . extra_data = sids_string ;
s3call - > response . length + = strlen ( sids_string ) + 1 ;
s3call - > response . data . num_entries = num_sids ;
2005-10-16 02:01:15 +04:00
done :
if ( ! NT_STATUS_IS_OK ( status ) ) {
struct winbindd_response * resp = & s3call - > response ;
resp - > result = WINBINDD_ERROR ;
WBSRV_SAMBA3_SET_STRING ( resp - > data . auth . nt_status_string ,
nt_errstr ( status ) ) ;
WBSRV_SAMBA3_SET_STRING ( resp - > data . auth . error_string ,
nt_errstr ( status ) ) ;
resp - > data . auth . pam_error = nt_status_to_pam ( status ) ;
}
status = wbsrv_send_reply ( s3call - > call ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
wbsrv_terminate_connection ( s3call - > call - > wbconn ,
" wbsrv_queue_reply() failed " ) ;
return ;
}
}
2005-10-07 23:08:51 +04:00
static void lookupname_recv_sid ( struct composite_context * ctx ) ;
2005-10-03 21:36:49 +04:00
NTSTATUS wbsrv_samba3_lookupname ( struct wbsrv_samba3_call * s3call )
{
struct composite_context * ctx ;
DEBUG ( 5 , ( " wbsrv_samba3_lookupname called \n " ) ) ;
2005-10-08 20:25:00 +04:00
ctx = wb_cmd_lookupname_send ( s3call - > call ,
s3call - > request . data . name . name ) ;
2005-10-03 21:36:49 +04:00
NT_STATUS_HAVE_NO_MEMORY ( ctx ) ;
/* setup the callbacks */
2005-10-08 20:25:00 +04:00
ctx - > async . fn = lookupname_recv_sid ;
ctx - > async . private_data = s3call ;
2005-10-03 21:36:49 +04:00
s3call - > call - > flags | = WBSRV_CALL_FLAGS_REPLY_ASYNC ;
return NT_STATUS_OK ;
}
2005-10-07 23:08:51 +04:00
static void lookupname_recv_sid ( struct composite_context * ctx )
{
2005-10-08 20:25:00 +04:00
struct wbsrv_samba3_call * s3call =
2005-10-07 23:08:51 +04:00
talloc_get_type ( ctx - > async . private_data ,
2005-10-08 20:25:00 +04:00
struct wbsrv_samba3_call ) ;
2005-10-07 23:08:51 +04:00
struct wb_sid_object * sid ;
2005-10-08 20:25:00 +04:00
NTSTATUS status ;
2005-10-07 23:08:51 +04:00
2005-10-08 20:25:00 +04:00
status = wb_cmd_lookupname_recv ( ctx , s3call , & sid ) ;
2005-10-07 23:08:51 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) goto done ;
2005-10-08 20:25:00 +04:00
s3call - > response . result = WINBINDD_OK ;
s3call - > response . data . sid . type = sid - > type ;
WBSRV_SAMBA3_SET_STRING ( s3call - > response . data . sid . sid ,
dom_sid_string ( s3call , sid - > sid ) ) ;
2005-10-07 23:08:51 +04:00
done :
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-10-08 20:25:00 +04:00
struct winbindd_response * resp = & s3call - > response ;
2005-10-07 23:08:51 +04:00
resp - > result = WINBINDD_ERROR ;
WBSRV_SAMBA3_SET_STRING ( resp - > data . auth . nt_status_string ,
nt_errstr ( status ) ) ;
WBSRV_SAMBA3_SET_STRING ( resp - > data . auth . error_string ,
nt_errstr ( status ) ) ;
resp - > data . auth . pam_error = nt_status_to_pam ( status ) ;
}
2005-10-08 20:25:00 +04:00
status = wbsrv_send_reply ( s3call - > call ) ;
2005-10-07 23:08:51 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2005-10-08 20:25:00 +04:00
wbsrv_terminate_connection ( s3call - > call - > wbconn ,
2005-10-07 23:08:51 +04:00
" wbsrv_queue_reply() failed " ) ;
return ;
}
}
2005-10-09 16:13:05 +04:00
NTSTATUS wbsrv_samba3_pam_auth ( struct wbsrv_samba3_call * s3call )
{
s3call - > response . result = WINBINDD_ERROR ;
return NT_STATUS_OK ;
}
2005-10-15 01:41:08 +04:00
#if 0
2005-10-15 01:05:45 +04:00
static BOOL samba3_parse_domuser ( TALLOC_CTX * mem_ctx , const char * domuser ,
char * * domain , char * * user )
2005-10-09 16:13:05 +04:00
{
2005-10-15 01:05:45 +04:00
char * p = strchr ( domuser , * lp_winbind_separator ( ) ) ;
2005-10-13 00:22:45 +04:00
2005-10-15 01:05:45 +04:00
if ( p = = NULL ) {
* domain = talloc_strdup ( mem_ctx , lp_workgroup ( ) ) ;
} else {
* domain = talloc_strndup ( mem_ctx , domuser ,
PTR_DIFF ( p , domuser ) ) ;
domuser = p + 1 ;
2005-10-09 16:13:05 +04:00
}
2005-10-15 01:05:45 +04:00
* user = talloc_strdup ( mem_ctx , domuser ) ;
return ( ( * domain ! = NULL ) & & ( * user ! = NULL ) ) ;
}
2005-10-15 01:41:08 +04:00
# endif
2005-10-15 01:05:45 +04:00
static void pam_auth_crap_recv ( struct composite_context * ctx ) ;
NTSTATUS wbsrv_samba3_pam_auth_crap ( struct wbsrv_samba3_call * s3call )
{
struct composite_context * ctx ;
2005-10-13 00:22:45 +04:00
DATA_BLOB chal , nt_resp , lm_resp ;
DEBUG ( 5 , ( " wbsrv_samba3_pam_auth_crap called \n " ) ) ;
chal . data = s3call - > request . data . auth_crap . chal ;
chal . length = sizeof ( s3call - > request . data . auth_crap . chal ) ;
nt_resp . data = s3call - > request . data . auth_crap . nt_resp ;
nt_resp . length = s3call - > request . data . auth_crap . nt_resp_len ;
lm_resp . data = s3call - > request . data . auth_crap . lm_resp ;
lm_resp . length = s3call - > request . data . auth_crap . lm_resp_len ;
2005-10-15 01:05:45 +04:00
ctx = wb_cmd_pam_auth_crap_send (
2005-10-15 01:41:08 +04:00
s3call - > call ,
s3call - > request . data . auth_crap . domain ,
s3call - > request . data . auth_crap . user ,
2005-10-15 01:05:45 +04:00
s3call - > request . data . auth_crap . workstation ,
chal , nt_resp , lm_resp ) ;
NT_STATUS_HAVE_NO_MEMORY ( ctx ) ;
ctx - > async . fn = pam_auth_crap_recv ;
ctx - > async . private_data = s3call ;
s3call - > call - > flags | = WBSRV_CALL_FLAGS_REPLY_ASYNC ;
return NT_STATUS_OK ;
}
static void pam_auth_crap_recv ( struct composite_context * ctx )
{
struct wbsrv_samba3_call * s3call =
talloc_get_type ( ctx - > async . private_data ,
struct wbsrv_samba3_call ) ;
struct winbindd_response * resp = & s3call - > response ;
NTSTATUS status ;
DATA_BLOB info3 ;
struct netr_UserSessionKey user_session_key ;
struct netr_LMSessionKey lm_key ;
status = wb_cmd_pam_auth_crap_recv ( ctx , s3call , & info3 ,
& user_session_key , & lm_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) goto done ;
if ( s3call - > request . flags & WBFLAG_PAM_USER_SESSION_KEY ) {
memcpy ( s3call - > response . data . auth . user_session_key ,
& user_session_key . key ,
sizeof ( s3call - > response . data . auth . user_session_key ) ) ;
}
if ( s3call - > request . flags & WBFLAG_PAM_INFO3_NDR ) {
s3call - > response . extra_data = info3 . data ;
s3call - > response . length + = info3 . length ;
}
if ( s3call - > request . flags & WBFLAG_PAM_LMKEY ) {
memcpy ( s3call - > response . data . auth . first_8_lm_hash ,
lm_key . key ,
sizeof ( s3call - > response . data . auth . first_8_lm_hash ) ) ;
}
resp - > result = WINBINDD_OK ;
done :
if ( ! NT_STATUS_IS_OK ( status ) ) {
resp - > result = WINBINDD_ERROR ;
WBSRV_SAMBA3_SET_STRING ( resp - > data . auth . nt_status_string ,
nt_errstr ( status ) ) ;
WBSRV_SAMBA3_SET_STRING ( resp - > data . auth . error_string ,
nt_errstr ( status ) ) ;
resp - > data . auth . pam_error = nt_status_to_pam ( status ) ;
}
status = wbsrv_send_reply ( s3call - > call ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
wbsrv_terminate_connection ( s3call - > call - > wbconn ,
" wbsrv_queue_reply() failed " ) ;
return ;
}
2005-10-09 16:13:05 +04:00
}