1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-23 09:57:40 +03:00

r991: Allow winbindd to use the domain trust account password

for setting up an schannel connection.  This solves the problem
of a Samba DC running winbind, trusting a native mode AD domain,
and needing to enumerate AD users via wbinfo -u.
This commit is contained in:
Gerald Carter 2004-06-03 18:00:22 +00:00 committed by Gerald (Jerry) Carter
parent 5070c1b68f
commit e9f109d1b3
10 changed files with 205 additions and 53 deletions

View File

@ -1425,8 +1425,10 @@ BOOL is_trusted_domain(const char* dom_name)
/* if we are a DC, then check for a direct trust relationships */ /* if we are a DC, then check for a direct trust relationships */
if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) { if ( IS_DC ) {
become_root(); become_root();
DEBUG (5,("is_trusted_domain: Checking for domain trust with [%s]\n",
dom_name ));
ret = secrets_fetch_trusted_domain_password(dom_name, &pass, &trustdom_sid, &lct); ret = secrets_fetch_trusted_domain_password(dom_name, &pass, &trustdom_sid, &lct);
unbecome_root(); unbecome_root();
SAFE_FREE(pass); SAFE_FREE(pass);

View File

@ -71,7 +71,8 @@ enum RPC_PKT_TYPE
to NT4. Actually, anything other than 1ff would seem to do... */ to NT4. Actually, anything other than 1ff would seem to do... */
#define NETLOGON_NEG_AUTH2_FLAGS 0x000701ff #define NETLOGON_NEG_AUTH2_FLAGS 0x000701ff
#define NETLOGON_NEG_SCHANNEL 0x40000000 #define NETLOGON_NEG_SCHANNEL 0x40000000
#define NETLOGON_NEG_DOMAIN_TRUST_ACCOUNT 0x2010b000
enum netsec_direction enum netsec_direction
{ {

View File

@ -68,6 +68,11 @@
#define SAM_DATABASE_BUILTIN 0x01 /* BUILTIN users and groups */ #define SAM_DATABASE_BUILTIN 0x01 /* BUILTIN users and groups */
#define SAM_DATABASE_PRIVS 0x02 /* Privileges */ #define SAM_DATABASE_PRIVS 0x02 /* Privileges */
#define NETLOGON_CONTROL_REDISCOVER 0x5
#define NETLOGON_CONTROL_TC_QUERY 0x6
#define NETLOGON_CONTROL_TRANSPORT_NOTIFY 0x7
#define NETLOGON_CONTROL_SET_DBFLAG 0xfffe
#if 0 #if 0
/* I think this is correct - it's what gets parsed on the wire. JRA. */ /* I think this is correct - it's what gets parsed on the wire. JRA. */
/* NET_USER_INFO_2 */ /* NET_USER_INFO_2 */
@ -204,7 +209,7 @@ typedef struct netlogon_2_info
uint32 flags; /* 0x0 - undocumented */ uint32 flags; /* 0x0 - undocumented */
uint32 pdc_status; /* 0x0 - undocumented */ uint32 pdc_status; /* 0x0 - undocumented */
uint32 ptr_trusted_dc_name; /* pointer to trusted domain controller name */ uint32 ptr_trusted_dc_name; /* pointer to trusted domain controller name */
uint32 tc_status; /* 0x051f - ERROR_NO_LOGON_SERVERS */ uint32 tc_status;
UNISTR2 uni_trusted_dc_name; /* unicode string - trusted dc name */ UNISTR2 uni_trusted_dc_name; /* unicode string - trusted dc name */
} NETLOGON_INFO_2; } NETLOGON_INFO_2;
@ -255,6 +260,26 @@ typedef struct net_r_logon_ctrl_info
NTSTATUS status; NTSTATUS status;
} NET_R_LOGON_CTRL; } NET_R_LOGON_CTRL;
typedef struct ctrl_data_info_5
{
uint32 function_code;
uint32 ptr_domain;
UNISTR2 domain;
} CTRL_DATA_INFO_5;
typedef struct ctrl_data_info_6
{
uint32 function_code;
uint32 ptr_domain;
UNISTR2 domain;
} CTRL_DATA_INFO_6;
/******************************************************** /********************************************************
Logon Control2 Query Logon Control2 Query
@ -266,13 +291,16 @@ typedef struct net_r_logon_ctrl_info
/* NET_Q_LOGON_CTRL2 - LSA Netr Logon Control 2 */ /* NET_Q_LOGON_CTRL2 - LSA Netr Logon Control 2 */
typedef struct net_q_logon_ctrl2_info typedef struct net_q_logon_ctrl2_info
{ {
uint32 ptr; /* undocumented buffer pointer */ uint32 ptr; /* undocumented buffer pointer */
UNISTR2 uni_server_name; /* server name, starting with two '\'s */ UNISTR2 uni_server_name; /* server name, starting with two '\'s */
uint32 function_code;
uint32 query_level;
union {
CTRL_DATA_INFO_5 info5;
CTRL_DATA_INFO_6 info6;;
} info;
uint32 function_code; /* 0x1 */
uint32 query_level; /* 0x1, 0x3 */
uint32 switch_value; /* 0x1 */
} NET_Q_LOGON_CTRL2; } NET_Q_LOGON_CTRL2;
/******************************************************* /*******************************************************

View File

@ -363,6 +363,12 @@ static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
if ( NT_STATUS_IS_OK(status) ) if ( NT_STATUS_IS_OK(status) )
goto done; goto done;
/* important! make sure that we know if this is a native
mode domain or not */
if ( !domain->initialized )
set_dc_type_and_flags( domain );
status = domain->backend->sequence_number(domain, &domain->sequence_number); status = domain->backend->sequence_number(domain, &domain->sequence_number);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {

View File

@ -117,21 +117,40 @@ static void cm_get_ipc_userpass(char **username, char **domain, char **password)
/* /*
setup for schannel on any pipes opened on this connection setup for schannel on any pipes opened on this connection
*/ */
static NTSTATUS setup_schannel(struct cli_state *cli) static NTSTATUS setup_schannel( struct cli_state *cli, const char *domain )
{ {
NTSTATUS ret; NTSTATUS ret;
uchar trust_password[16]; uchar trust_password[16];
uint32 sec_channel_type; uint32 sec_channel_type;
DOM_SID sid;
time_t lct;
if (!secrets_fetch_trust_account_password(lp_workgroup(), /* use the domain trust password if we're on a DC
trust_password, and this is not our domain */
NULL, &sec_channel_type)) {
return NT_STATUS_UNSUCCESSFUL; if ( IS_DC && !strequal(domain, lp_workgroup()) ) {
char *pass = NULL;
if ( !secrets_fetch_trusted_domain_password( domain,
&pass, &sid, &lct) )
{
return NT_STATUS_UNSUCCESSFUL;
}
sec_channel_type = SEC_CHAN_DOMAIN;
E_md4hash(pass, trust_password);
SAFE_FREE( pass );
} else {
if (!secrets_fetch_trust_account_password(lp_workgroup(),
trust_password, NULL, &sec_channel_type))
{
return NT_STATUS_UNSUCCESSFUL;
}
} }
ret = cli_nt_setup_netsec(cli, sec_channel_type, ret = cli_nt_setup_netsec(cli, sec_channel_type,
AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, trust_password);
trust_password);
return ret; return ret;
} }
@ -216,7 +235,8 @@ static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const i
/* Initialise SMB connection */ /* Initialise SMB connection */
fstrcpy(new_conn->pipe_name, get_pipe_name_from_index(pipe_index)); fstrcpy(new_conn->pipe_name, get_pipe_name_from_index(pipe_index));
/* grab stored passwords */ /* grab stored passwords */
machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) { if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) {
@ -335,9 +355,13 @@ static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const i
/* try and use schannel if possible, but continue anyway if it /* try and use schannel if possible, but continue anyway if it
failed. This allows existing setups to continue working, failed. This allows existing setups to continue working,
while solving the win2003 '100 user' limit for systems that while solving the win2003 '100 user' limit for systems that
are joined properly */ are joined properly.
if (NT_STATUS_IS_OK(result) && (domain->primary)) {
NTSTATUS status = setup_schannel(new_conn->cli); Only do this for our own domain or perhaps a trusted domain
if we are on a Samba DC */
if (NT_STATUS_IS_OK(result) && (domain->primary || IS_DC) ) {
NTSTATUS status = setup_schannel( new_conn->cli, domain->name );
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
DEBUG(3,("schannel refused - continuing without schannel (%s)\n", DEBUG(3,("schannel refused - continuing without schannel (%s)\n",
nt_errstr(status))); nt_errstr(status)));

View File

@ -91,18 +91,25 @@ NTSTATUS cli_net_auth2(struct cli_state *cli,
NET_Q_AUTH_2 q; NET_Q_AUTH_2 q;
NET_R_AUTH_2 r; NET_R_AUTH_2 r;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL; NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
fstring machine_acct;
prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL); prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL); prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
if ( sec_chan == SEC_CHAN_DOMAIN )
fstr_sprintf( machine_acct, "%s$", lp_workgroup() );
else
fstrcpy( machine_acct, cli->mach_acct );
/* create and send a MSRPC command with api NET_AUTH2 */ /* create and send a MSRPC command with api NET_AUTH2 */
DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n", DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname(), cli->srv_name_slash, machine_acct, sec_chan, global_myname(),
credstr(cli->clnt_cred.challenge.data), *neg_flags)); credstr(cli->clnt_cred.challenge.data), *neg_flags));
/* store the parameters */ /* store the parameters */
init_q_auth_2(&q, cli->srv_name_slash, cli->mach_acct,
init_q_auth_2(&q, cli->srv_name_slash, machine_acct,
sec_chan, global_myname(), &cli->clnt_cred.challenge, sec_chan, global_myname(), &cli->clnt_cred.challenge,
*neg_flags); *neg_flags);

View File

@ -1621,9 +1621,6 @@ NTSTATUS cli_nt_setup_netsec(struct cli_state *cli, int sec_chan, int auth_flags
return NT_STATUS_UNSUCCESSFUL; return NT_STATUS_UNSUCCESSFUL;
} }
if (lp_client_schannel() != False)
neg_flags |= NETLOGON_NEG_SCHANNEL;
neg_flags |= NETLOGON_NEG_SCHANNEL; neg_flags |= NETLOGON_NEG_SCHANNEL;
result = cli_nt_setup_creds(cli, sec_chan, trust_password, result = cli_nt_setup_creds(cli, sec_chan, trust_password,

View File

@ -182,6 +182,50 @@ static BOOL net_io_netinfo_2(const char *desc, NETLOGON_INFO_2 *info, prs_struct
return True; return True;
} }
static BOOL net_io_ctrl_data_info_5(const char *desc, CTRL_DATA_INFO_5 *info, prs_struct *ps, int depth)
{
if (info == NULL)
return False;
prs_debug(ps, depth, desc, "net_io_ctrl_data_info_5");
depth++;
if ( !prs_uint32( "function_code", ps, depth, &info->function_code ) )
return False;
if(!prs_uint32("ptr_domain", ps, depth, &info->ptr_domain))
return False;
if ( info->ptr_domain ) {
if(!smb_io_unistr2("domain", &info->domain, info->ptr_domain, ps, depth))
return False;
}
return True;
}
static BOOL net_io_ctrl_data_info_6(const char *desc, CTRL_DATA_INFO_6 *info, prs_struct *ps, int depth)
{
if (info == NULL)
return False;
prs_debug(ps, depth, desc, "net_io_ctrl_data_info_6");
depth++;
if ( !prs_uint32( "function_code", ps, depth, &info->function_code ) )
return False;
if(!prs_uint32("ptr_domain", ps, depth, &info->ptr_domain))
return False;
if ( info->ptr_domain ) {
if(!smb_io_unistr2("domain", &info->domain, info->ptr_domain, ps, depth))
return False;
}
return True;
}
/******************************************************************* /*******************************************************************
Reads or writes an NET_Q_LOGON_CTRL2 structure. Reads or writes an NET_Q_LOGON_CTRL2 structure.
********************************************************************/ ********************************************************************/
@ -210,9 +254,23 @@ BOOL net_io_q_logon_ctrl2(const char *desc, NET_Q_LOGON_CTRL2 *q_l, prs_struct *
return False; return False;
if(!prs_uint32("query_level ", ps, depth, &q_l->query_level)) if(!prs_uint32("query_level ", ps, depth, &q_l->query_level))
return False; return False;
if(!prs_uint32("switch_value ", ps, depth, &q_l->switch_value)) switch ( q_l->function_code ) {
return False; case NETLOGON_CONTROL_REDISCOVER:
if ( !net_io_ctrl_data_info_5( "ctrl_data_info5", &q_l->info.info5, ps, depth) )
return False;
break;
case NETLOGON_CONTROL_TC_QUERY:
if ( !net_io_ctrl_data_info_6( "ctrl_data_info6", &q_l->info.info6, ps, depth) )
return False;
break;
default:
DEBUG(0,("net_io_q_logon_ctrl2: unknown function_code [%d]\n",
q_l->function_code));
return False;
}
return True; return True;
} }
@ -227,7 +285,6 @@ void init_net_q_logon_ctrl2(NET_Q_LOGON_CTRL2 *q_l, const char *srv_name,
q_l->function_code = 0x01; q_l->function_code = 0x01;
q_l->query_level = query_level; q_l->query_level = query_level;
q_l->switch_value = 0x01;
init_unistr2(&q_l->uni_server_name, srv_name, UNI_STR_TERMINATE); init_unistr2(&q_l->uni_server_name, srv_name, UNI_STR_TERMINATE);
} }
@ -241,9 +298,7 @@ void init_net_r_logon_ctrl2(NET_R_LOGON_CTRL2 *r_l, uint32 query_level,
uint32 logon_attempts, uint32 tc_status, uint32 logon_attempts, uint32 tc_status,
const char *trusted_domain_name) const char *trusted_domain_name)
{ {
DEBUG(5,("init_r_logon_ctrl2\n")); r_l->switch_value = query_level;
r_l->switch_value = query_level; /* should only be 0x1 */
switch (query_level) { switch (query_level) {
case 1: case 1:

View File

@ -227,8 +227,6 @@ static BOOL api_net_trust_dom_list(pipes_struct *p)
ZERO_STRUCT(q_u); ZERO_STRUCT(q_u);
ZERO_STRUCT(r_u); ZERO_STRUCT(r_u);
DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
/* grab the lsa trusted domain list query... */ /* grab the lsa trusted domain list query... */
if(!net_io_q_trust_dom("", &q_u, data, 0)) { if(!net_io_q_trust_dom("", &q_u, data, 0)) {
DEBUG(0,("api_net_trust_dom_list: Failed to unmarshall NET_Q_TRUST_DOM_LIST.\n")); DEBUG(0,("api_net_trust_dom_list: Failed to unmarshall NET_Q_TRUST_DOM_LIST.\n"));
@ -244,8 +242,6 @@ static BOOL api_net_trust_dom_list(pipes_struct *p)
return False; return False;
} }
DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
return True; return True;
} }
@ -263,7 +259,6 @@ static BOOL api_net_logon_ctrl2(pipes_struct *p)
ZERO_STRUCT(q_u); ZERO_STRUCT(q_u);
ZERO_STRUCT(r_u); ZERO_STRUCT(r_u);
DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
/* grab the lsa netlogon ctrl2 query... */ /* grab the lsa netlogon ctrl2 query... */
if(!net_io_q_logon_ctrl2("", &q_u, data, 0)) { if(!net_io_q_logon_ctrl2("", &q_u, data, 0)) {
@ -278,8 +273,6 @@ static BOOL api_net_logon_ctrl2(pipes_struct *p)
return False; return False;
} }
DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
return True; return True;
} }
@ -297,8 +290,6 @@ static BOOL api_net_logon_ctrl(pipes_struct *p)
ZERO_STRUCT(q_u); ZERO_STRUCT(q_u);
ZERO_STRUCT(r_u); ZERO_STRUCT(r_u);
DEBUG(6,("api_net_logon_ctrl: %d\n", __LINE__));
/* grab the lsa netlogon ctrl query... */ /* grab the lsa netlogon ctrl query... */
if(!net_io_q_logon_ctrl("", &q_u, data, 0)) { if(!net_io_q_logon_ctrl("", &q_u, data, 0)) {
DEBUG(0,("api_net_logon_ctrl: Failed to unmarshall NET_Q_LOGON_CTRL.\n")); DEBUG(0,("api_net_logon_ctrl: Failed to unmarshall NET_Q_LOGON_CTRL.\n"));
@ -312,8 +303,6 @@ static BOOL api_net_logon_ctrl(pipes_struct *p)
return False; return False;
} }
DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
return True; return True;
} }

View File

@ -47,6 +47,7 @@ static void init_net_r_req_chal(NET_R_REQ_CHAL *r_c,
#define ERROR_NO_SUCH_DOMAIN 0x54b #define ERROR_NO_SUCH_DOMAIN 0x54b
#define ERROR_NO_LOGON_SERVERS 0x51f #define ERROR_NO_LOGON_SERVERS 0x51f
#define NO_ERROR 0x0
/************************************************************************* /*************************************************************************
net_reply_logon_ctrl: net_reply_logon_ctrl:
@ -104,25 +105,67 @@ NTSTATUS _net_logon_ctrl2(pipes_struct *p, NET_Q_LOGON_CTRL2 *q_u, NET_R_LOGON_C
uint32 flags = 0x0; uint32 flags = 0x0;
uint32 pdc_connection_status = 0x0; uint32 pdc_connection_status = 0x0;
uint32 logon_attempts = 0x0; uint32 logon_attempts = 0x0;
uint32 tc_status = ERROR_NO_LOGON_SERVERS; uint32 tc_status;
const char *trusted_domain = "test_domain"; fstring servername, domain, dc_name, dc_name2;
struct in_addr dc_ip;
DEBUG(0, ("*** net long ctrl2 %d, %d, %d\n", /* this should be \\global_myname() */
q_u->function_code, q_u->query_level, q_u->switch_value)); unistr2_to_ascii(servername, &q_u->uni_server_name, sizeof(servername));
DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__)); r_u->status = NT_STATUS_OK;
tc_status = ERROR_NO_SUCH_DOMAIN;
fstrcpy( dc_name, "" );
switch ( q_u->function_code ) {
case NETLOGON_CONTROL_TC_QUERY:
unistr2_to_ascii(domain, &q_u->info.info6.domain, sizeof(domain));
if ( !is_trusted_domain( domain ) )
break;
if ( !get_dc_name( domain, NULL, dc_name2, &dc_ip ) ) {
tc_status = ERROR_NO_LOGON_SERVERS;
break;
}
fstr_sprintf( dc_name, "\\\\%s", dc_name2 );
tc_status = NO_ERROR;
break;
case NETLOGON_CONTROL_REDISCOVER:
unistr2_to_ascii(domain, &q_u->info.info6.domain, sizeof(domain));
if ( !is_trusted_domain( domain ) )
break;
if ( !get_dc_name( domain, NULL, dc_name2, &dc_ip ) ) {
tc_status = ERROR_NO_LOGON_SERVERS;
break;
}
/* set up the Logon Control2 response */ fstr_sprintf( dc_name, "\\\\%s", dc_name2 );
init_net_r_logon_ctrl2(r_u, q_u->query_level,
flags, pdc_connection_status, logon_attempts, tc_status = NO_ERROR;
tc_status, trusted_domain);
break;
default:
/* no idea what this should be */
DEBUG(0,("_net_logon_ctrl2: unimplemented function level [%d]\n",
q_u->function_code));
}
/* prepare the response */
init_net_r_logon_ctrl2( r_u, q_u->query_level, flags,
pdc_connection_status, logon_attempts, tc_status, dc_name );
if (lp_server_role() == ROLE_DOMAIN_BDC) if (lp_server_role() == ROLE_DOMAIN_BDC)
send_sync_message(); send_sync_message();
DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
return r_u->status; return r_u->status;
} }