2005-01-14 05:01:19 +03:00
/*
Unix SMB / CIFS implementation .
Main winbindd server routines
2010-02-18 02:54:53 +03:00
Copyright ( C ) Stefan Metzmacher 2005 - 2008
2005-01-30 05:55:30 +03:00
Copyright ( C ) Andrew Tridgell 2005
2010-02-18 02:54:53 +03:00
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2010
2005-01-14 05:01:19 +03: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-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-01-14 05:01:19 +03:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-01-14 05:01:19 +03:00
*/
# include "includes.h"
2006-03-07 14:07:23 +03:00
# include "smbd/process_model.h"
2005-09-22 22:35:08 +04:00
# include "winbind/wb_server.h"
2006-01-12 12:38:35 +03:00
# include "lib/stream/packet.h"
2010-01-17 12:21:21 +03:00
# include "lib/tsocket/tsocket.h"
# include "libcli/util/tstream.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2010-02-18 02:54:53 +03:00
# include "param/secrets.h"
2005-01-14 05:01:19 +03:00
2005-09-22 22:35:08 +04:00
void wbsrv_terminate_connection ( struct wbsrv_connection * wbconn , const char * reason )
{
stream_terminate_connection ( wbconn - > conn , reason ) ;
}
2005-01-14 05:01:19 +03:00
2010-01-17 12:21:21 +03:00
static void wbsrv_call_loop ( struct tevent_req * subreq )
2006-01-12 12:38:35 +03:00
{
2010-01-17 12:21:21 +03:00
struct wbsrv_connection * wbsrv_conn = tevent_req_callback_data ( subreq ,
struct wbsrv_connection ) ;
struct wbsrv_samba3_call * call ;
NTSTATUS status ;
call = talloc_zero ( wbsrv_conn , struct wbsrv_samba3_call ) ;
if ( call = = NULL ) {
wbsrv_terminate_connection ( wbsrv_conn , " wbsrv_call_loop: "
" no memory for wbsrv_samba3_call " ) ;
return ;
}
call - > wbconn = wbsrv_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 , " wbsrv_call_loop: "
" tstream_read_pdu_blob_recv() - %s " ,
nt_errstr ( status ) ) ;
if ( ! reason ) {
reason = nt_errstr ( status ) ;
}
wbsrv_terminate_connection ( wbsrv_conn , reason ) ;
return ;
}
DEBUG ( 10 , ( " Received winbind TCP packet of length %lu from %s \n " ,
( long ) call - > in . length ,
tsocket_address_string ( wbsrv_conn - > conn - > remote_address , call ) ) ) ;
status = wbsrv_samba3_process ( call ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
const char * reason ;
reason = talloc_asprintf ( call , " wbsrv_call_loop: "
" tstream_read_pdu_blob_recv() - %s " ,
nt_errstr ( status ) ) ;
if ( ! reason ) {
reason = nt_errstr ( status ) ;
}
wbsrv_terminate_connection ( wbsrv_conn , reason ) ;
return ;
}
/*
* The winbind pdu ' s has the length as 4 byte ( initial_read_size ) ,
* wbsrv_samba3_packet_full_request provides the pdu length then .
*/
subreq = tstream_read_pdu_blob_send ( wbsrv_conn ,
wbsrv_conn - > conn - > event . ctx ,
wbsrv_conn - > tstream ,
4 , /* initial_read_size */
wbsrv_samba3_packet_full_request ,
wbsrv_conn ) ;
if ( subreq = = NULL ) {
wbsrv_terminate_connection ( wbsrv_conn , " wbsrv_call_loop: "
" no memory for tstream_read_pdu_blob_send " ) ;
return ;
}
tevent_req_set_callback ( subreq , wbsrv_call_loop , wbsrv_conn ) ;
2006-01-12 12:38:35 +03:00
}
2005-09-22 22:35:08 +04:00
static void wbsrv_accept ( struct stream_connection * conn )
2005-01-14 05:01:19 +03:00
{
2010-01-17 12:21:21 +03:00
struct wbsrv_listen_socket * wbsrv_socket = talloc_get_type ( conn - > private_data ,
struct wbsrv_listen_socket ) ;
struct wbsrv_connection * wbsrv_conn ;
struct tevent_req * subreq ;
int rc ;
2005-01-14 05:01:19 +03:00
2010-01-17 12:21:21 +03:00
wbsrv_conn = talloc_zero ( conn , struct wbsrv_connection ) ;
if ( wbsrv_conn = = NULL ) {
2006-01-12 12:38:35 +03:00
stream_terminate_connection ( conn , " wbsrv_accept: out of memory " ) ;
2005-01-14 05:01:19 +03:00
return ;
}
2010-01-17 12:21:21 +03:00
wbsrv_conn - > send_queue = tevent_queue_create ( conn , " wbsrv_accept " ) ;
if ( wbsrv_conn - > send_queue = = NULL ) {
stream_terminate_connection ( conn ,
" wbsrv_accept: out of memory " ) ;
2005-09-21 00:54:25 +04:00
return ;
}
2010-01-17 12:21:21 +03:00
TALLOC_FREE ( conn - > event . fde ) ;
2010-02-26 12:21:10 +03:00
rc = tstream_bsd_existing_socket ( wbsrv_conn ,
2010-01-17 12:21:21 +03:00
socket_get_fd ( conn - > socket ) ,
& wbsrv_conn - > tstream ) ;
if ( rc < 0 ) {
stream_terminate_connection ( conn ,
" wbsrv_accept: out of memory " ) ;
return ;
}
wbsrv_conn - > conn = conn ;
wbsrv_conn - > listen_socket = wbsrv_socket ;
wbsrv_conn - > lp_ctx = wbsrv_socket - > service - > task - > lp_ctx ;
conn - > private_data = wbsrv_conn ;
/*
* The winbind pdu ' s has the length as 4 byte ( initial_read_size ) ,
* wbsrv_samba3_packet_full_request provides the pdu length then .
*/
subreq = tstream_read_pdu_blob_send ( wbsrv_conn ,
wbsrv_conn - > conn - > event . ctx ,
wbsrv_conn - > tstream ,
4 , /* initial_read_size */
wbsrv_samba3_packet_full_request ,
wbsrv_conn ) ;
if ( subreq = = NULL ) {
wbsrv_terminate_connection ( wbsrv_conn , " wbsrv_accept: "
" no memory for tstream_read_pdu_blob_send " ) ;
return ;
}
tevent_req_set_callback ( subreq , wbsrv_call_loop , wbsrv_conn ) ;
2005-09-21 00:54:25 +04:00
}
2005-09-22 22:35:08 +04:00
/*
2010-01-17 12:21:21 +03:00
called on a tcp recv
2006-01-12 12:38:35 +03:00
*/
static void wbsrv_recv ( struct stream_connection * conn , uint16_t flags )
2005-09-21 00:54:25 +04:00
{
2010-01-17 12:21:21 +03:00
struct wbsrv_connection * wbsrv_conn = talloc_get_type ( conn - > private_data ,
struct wbsrv_connection ) ;
wbsrv_terminate_connection ( wbsrv_conn , " wbsrv_recv: called " ) ;
2005-09-21 00:54:25 +04:00
}
2005-09-22 22:35:08 +04:00
/*
called when we can write to a connection
*/
static void wbsrv_send ( struct stream_connection * conn , uint16_t flags )
2005-09-21 00:54:25 +04:00
{
2010-01-17 12:21:21 +03:00
struct wbsrv_connection * wbsrv_conn = talloc_get_type ( conn - > private_data ,
struct wbsrv_connection ) ;
/* this should never be triggered! */
wbsrv_terminate_connection ( wbsrv_conn , " wbsrv_send: called " ) ;
2005-09-21 00:54:25 +04:00
}
2005-09-22 22:35:08 +04:00
static const struct stream_server_ops wbsrv_ops = {
2006-01-12 12:38:35 +03:00
. name = " winbind samba3 protocol " ,
2005-09-22 22:35:08 +04:00
. accept_connection = wbsrv_accept ,
. recv_handler = wbsrv_recv ,
. send_handler = wbsrv_send
} ;
2005-01-30 05:55:30 +03:00
/*
startup the winbind task
*/
static void winbind_task_init ( struct task_server * task )
2005-01-14 05:01:19 +03:00
{
uint16_t port = 1 ;
2005-01-30 05:55:30 +03:00
const struct model_ops * model_ops ;
NTSTATUS status ;
2005-09-22 22:35:08 +04:00
struct wbsrv_service * service ;
struct wbsrv_listen_socket * listen_socket ;
2010-02-18 02:54:53 +03:00
char * errstring ;
struct dom_sid * primary_sid ;
2005-01-14 05:01:19 +03:00
2006-03-09 20:48:41 +03:00
task_server_set_title ( task , " task[winbind] " ) ;
2005-01-30 05:55:30 +03:00
/* within the winbind task we want to be a single process, so
ask for the single process model ops and pass these to the
stream_setup_socket ( ) call . */
2010-10-30 04:24:15 +04:00
model_ops = process_model_startup ( " single " ) ;
2005-01-30 05:55:30 +03:00
if ( ! model_ops ) {
2005-10-09 12:32:06 +04:00
task_server_terminate ( task ,
2009-09-19 05:05:55 +04:00
" Can't find 'single' process model_ops " , true ) ;
2005-01-30 05:55:30 +03:00
return ;
}
2005-01-14 05:01:19 +03:00
2006-01-31 03:48:57 +03:00
/* Make sure the directory for the Samba3 socket exists, and is of the correct permissions */
2010-07-16 08:32:42 +04:00
if ( ! directory_create_or_exist ( lpcfg_winbindd_socket_directory ( task - > lp_ctx ) , geteuid ( ) , 0755 ) ) {
2006-01-31 03:48:57 +03:00
task_server_terminate ( task ,
2009-09-19 05:05:55 +04:00
" Cannot create winbindd pipe directory " , true ) ;
2006-01-31 03:48:57 +03:00
return ;
2005-01-14 05:01:19 +03:00
}
2008-06-28 16:02:19 +04:00
/* Make sure the directory for the Samba3 socket exists, and is of the correct permissions */
2010-07-16 08:32:42 +04:00
if ( ! directory_create_or_exist ( lpcfg_winbindd_privileged_socket_directory ( task - > lp_ctx ) , geteuid ( ) , 0750 ) ) {
2008-06-28 16:02:19 +04:00
task_server_terminate ( task ,
2009-09-19 05:05:55 +04:00
" Cannot create winbindd privileged pipe directory " , true ) ;
2008-06-28 16:02:19 +04:00
return ;
}
2005-09-22 22:35:08 +04:00
service = talloc_zero ( task , struct wbsrv_service ) ;
if ( ! service ) goto nomem ;
service - > task = task ;
2010-02-18 02:54:53 +03:00
/* Find the primary SID, depending if we are a standalone
* server ( what good is winbind in this case , but anyway . . . ) ,
* or are in a domain as a member or a DC */
2010-07-16 08:32:42 +04:00
switch ( lpcfg_server_role ( service - > task - > lp_ctx ) ) {
2010-02-18 02:54:53 +03:00
case ROLE_STANDALONE :
primary_sid = secrets_get_domain_sid ( service ,
service - > task - > lp_ctx ,
2010-09-13 06:15:52 +04:00
lpcfg_netbios_name ( service - > task - > lp_ctx ) ,
& service - > sec_channel_type ,
& errstring ) ;
2010-02-18 02:54:53 +03:00
if ( ! primary_sid ) {
2010-02-19 03:14:15 +03:00
char * message = talloc_asprintf ( task ,
" Cannot start Winbind (standalone configuration): %s: "
" Have you provisioned this server (%s) or changed it's name? " ,
2010-07-16 08:32:42 +04:00
errstring , lpcfg_netbios_name ( service - > task - > lp_ctx ) ) ;
2010-02-18 02:54:53 +03:00
task_server_terminate ( task , message , true ) ;
return ;
}
break ;
case ROLE_DOMAIN_MEMBER :
2010-02-19 03:14:15 +03:00
primary_sid = secrets_get_domain_sid ( service ,
service - > task - > lp_ctx ,
2010-09-13 06:15:52 +04:00
lpcfg_workgroup ( service - > task - > lp_ctx ) ,
& service - > sec_channel_type ,
& errstring ) ;
2010-02-19 03:14:15 +03:00
if ( ! primary_sid ) {
char * message = talloc_asprintf ( task , " Cannot start Winbind (domain member): %s: "
" Have you joined the %s domain? " ,
2010-07-16 08:32:42 +04:00
errstring , lpcfg_workgroup ( service - > task - > lp_ctx ) ) ;
2010-02-19 03:14:15 +03:00
task_server_terminate ( task , message , true ) ;
return ;
}
break ;
2012-06-10 16:08:20 +04:00
case ROLE_ACTIVE_DIRECTORY_DC :
2010-02-18 02:54:53 +03:00
primary_sid = secrets_get_domain_sid ( service ,
service - > task - > lp_ctx ,
2010-09-13 06:15:52 +04:00
lpcfg_workgroup ( service - > task - > lp_ctx ) ,
& service - > sec_channel_type ,
& errstring ) ;
2010-02-18 02:54:53 +03:00
if ( ! primary_sid ) {
2010-02-19 03:14:15 +03:00
char * message = talloc_asprintf ( task , " Cannot start Winbind (domain controller): %s: "
" Have you provisioned the %s domain? " ,
2010-07-16 08:32:42 +04:00
errstring , lpcfg_workgroup ( service - > task - > lp_ctx ) ) ;
2010-02-18 02:54:53 +03:00
task_server_terminate ( task , message , true ) ;
return ;
}
break ;
2012-06-10 16:08:20 +04:00
case ROLE_DOMAIN_PDC :
case ROLE_DOMAIN_BDC :
task_server_terminate ( task , " Cannot start 'samba' winbindd as a 'classic samba' DC: use winbindd instead " , true ) ;
return ;
2005-10-09 16:50:35 +04:00
}
2010-02-18 02:54:53 +03:00
service - > primary_sid = primary_sid ;
2005-10-09 16:50:35 +04:00
2008-04-17 14:23:44 +04:00
service - > idmap_ctx = idmap_init ( service , task - > event_ctx , task - > lp_ctx ) ;
2008-02-18 16:33:58 +03:00
if ( service - > idmap_ctx = = NULL ) {
2009-09-19 05:05:55 +04:00
task_server_terminate ( task , " Failed to load idmap database " , true ) ;
2008-02-18 16:33:58 +03:00
return ;
}
2010-07-16 08:32:42 +04:00
service - > priv_pipe_dir = lpcfg_winbindd_privileged_socket_directory ( task - > lp_ctx ) ;
service - > pipe_dir = lpcfg_winbindd_socket_directory ( task - > lp_ctx ) ;
2010-05-17 13:54:00 +04:00
2005-09-22 22:35:08 +04:00
/* setup the unprivileged samba3 socket */
listen_socket = talloc ( service , struct wbsrv_listen_socket ) ;
if ( ! listen_socket ) goto nomem ;
2006-01-31 03:48:57 +03:00
listen_socket - > socket_path = talloc_asprintf ( listen_socket , " %s/%s " ,
2010-05-17 13:54:00 +04:00
service - > pipe_dir ,
2010-04-15 11:29:33 +04:00
WINBINDD_SOCKET_NAME ) ;
2005-09-22 22:35:08 +04:00
if ( ! listen_socket - > socket_path ) goto nomem ;
listen_socket - > service = service ;
2007-10-02 02:13:02 +04:00
listen_socket - > privileged = false ;
2010-11-15 02:12:22 +03:00
status = stream_setup_socket ( task , task - > event_ctx , task - > lp_ctx , model_ops ,
2005-09-22 22:35:08 +04:00
& wbsrv_ops , " unix " ,
2005-10-09 12:32:06 +04:00
listen_socket - > socket_path , & port ,
2010-07-16 08:32:42 +04:00
lpcfg_socket_options ( task - > lp_ctx ) ,
2005-10-09 12:32:06 +04:00
listen_socket ) ;
2005-09-22 22:35:08 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) goto listen_failed ;
/* setup the privileged samba3 socket */
listen_socket = talloc ( service , struct wbsrv_listen_socket ) ;
if ( ! listen_socket ) goto nomem ;
2008-09-10 08:08:40 +04:00
listen_socket - > socket_path
= talloc_asprintf ( listen_socket , " %s/%s " ,
2010-05-17 13:54:00 +04:00
service - > priv_pipe_dir ,
2010-04-15 11:29:33 +04:00
WINBINDD_SOCKET_NAME ) ;
2008-06-28 16:02:19 +04:00
if ( ! listen_socket - > socket_path ) goto nomem ;
2005-09-22 22:35:08 +04:00
listen_socket - > service = service ;
2007-10-02 02:13:02 +04:00
listen_socket - > privileged = true ;
2010-11-15 02:12:22 +03:00
status = stream_setup_socket ( task , task - > event_ctx , task - > lp_ctx , model_ops ,
2005-09-22 22:35:08 +04:00
& wbsrv_ops , " unix " ,
2005-10-09 12:32:06 +04:00
listen_socket - > socket_path , & port ,
2010-07-16 08:32:42 +04:00
lpcfg_socket_options ( task - > lp_ctx ) ,
2005-10-09 12:32:06 +04:00
listen_socket ) ;
2005-09-22 22:35:08 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) goto listen_failed ;
2006-07-31 19:38:18 +04:00
status = wbsrv_init_irpc ( service ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) goto irpc_failed ;
2005-09-22 22:35:08 +04:00
return ;
listen_failed :
DEBUG ( 0 , ( " stream_setup_socket(path=%s) failed - %s \n " ,
listen_socket - > socket_path , nt_errstr ( status ) ) ) ;
2009-09-19 05:05:55 +04:00
task_server_terminate ( task , nt_errstr ( status ) , true ) ;
2005-09-22 22:35:08 +04:00
return ;
2006-07-31 19:38:18 +04:00
irpc_failed :
DEBUG ( 0 , ( " wbsrv_init_irpc() failed - %s \n " ,
nt_errstr ( status ) ) ) ;
2009-09-19 05:05:55 +04:00
task_server_terminate ( task , nt_errstr ( status ) , true ) ;
2006-07-31 19:38:18 +04:00
return ;
2005-09-22 22:35:08 +04:00
nomem :
2009-09-19 05:05:55 +04:00
task_server_terminate ( task , nt_errstr ( NT_STATUS_NO_MEMORY ) , true ) ;
2005-09-22 22:35:08 +04:00
return ;
2005-01-14 05:01:19 +03:00
}
2005-01-30 05:55:30 +03:00
/*
register ourselves as a available server
*/
2005-01-14 05:01:19 +03:00
NTSTATUS server_service_winbind_init ( void )
{
2008-02-04 13:58:29 +03:00
return register_server_service ( " winbind " , winbind_task_init ) ;
2005-01-14 05:01:19 +03:00
}