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:
parent
5070c1b68f
commit
e9f109d1b3
@ -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 (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) {
|
||||
if ( IS_DC ) {
|
||||
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);
|
||||
unbecome_root();
|
||||
SAFE_FREE(pass);
|
||||
|
@ -71,7 +71,8 @@ enum RPC_PKT_TYPE
|
||||
to NT4. Actually, anything other than 1ff would seem to do... */
|
||||
#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
|
||||
{
|
||||
|
@ -68,6 +68,11 @@
|
||||
#define SAM_DATABASE_BUILTIN 0x01 /* BUILTIN users and groups */
|
||||
#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
|
||||
/* I think this is correct - it's what gets parsed on the wire. JRA. */
|
||||
/* NET_USER_INFO_2 */
|
||||
@ -204,7 +209,7 @@ typedef struct netlogon_2_info
|
||||
uint32 flags; /* 0x0 - undocumented */
|
||||
uint32 pdc_status; /* 0x0 - undocumented */
|
||||
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 */
|
||||
|
||||
} NETLOGON_INFO_2;
|
||||
@ -255,6 +260,26 @@ typedef struct net_r_logon_ctrl_info
|
||||
NTSTATUS status;
|
||||
} 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
|
||||
|
||||
@ -266,13 +291,16 @@ typedef struct net_r_logon_ctrl_info
|
||||
/* NET_Q_LOGON_CTRL2 - LSA Netr Logon Control 2 */
|
||||
typedef struct net_q_logon_ctrl2_info
|
||||
{
|
||||
uint32 ptr; /* undocumented buffer pointer */
|
||||
UNISTR2 uni_server_name; /* server name, starting with two '\'s */
|
||||
uint32 ptr; /* undocumented buffer pointer */
|
||||
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;
|
||||
|
||||
/*******************************************************
|
||||
|
@ -363,6 +363,12 @@ static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
|
||||
if ( NT_STATUS_IS_OK(status) )
|
||||
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);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
|
@ -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
|
||||
*/
|
||||
static NTSTATUS setup_schannel(struct cli_state *cli)
|
||||
static NTSTATUS setup_schannel( struct cli_state *cli, const char *domain )
|
||||
{
|
||||
NTSTATUS ret;
|
||||
uchar trust_password[16];
|
||||
uint32 sec_channel_type;
|
||||
DOM_SID sid;
|
||||
time_t lct;
|
||||
|
||||
if (!secrets_fetch_trust_account_password(lp_workgroup(),
|
||||
trust_password,
|
||||
NULL, &sec_channel_type)) {
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
/* use the domain trust password if we're on a DC
|
||||
and this is not our domain */
|
||||
|
||||
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,
|
||||
AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN,
|
||||
trust_password);
|
||||
AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, trust_password);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -216,7 +235,8 @@ static NTSTATUS cm_open_connection(const struct winbindd_domain *domain, const i
|
||||
/* Initialise SMB connection */
|
||||
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);
|
||||
|
||||
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
|
||||
failed. This allows existing setups to continue working,
|
||||
while solving the win2003 '100 user' limit for systems that
|
||||
are joined properly */
|
||||
if (NT_STATUS_IS_OK(result) && (domain->primary)) {
|
||||
NTSTATUS status = setup_schannel(new_conn->cli);
|
||||
are joined properly.
|
||||
|
||||
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)) {
|
||||
DEBUG(3,("schannel refused - continuing without schannel (%s)\n",
|
||||
nt_errstr(status)));
|
||||
|
@ -91,18 +91,25 @@ NTSTATUS cli_net_auth2(struct cli_state *cli,
|
||||
NET_Q_AUTH_2 q;
|
||||
NET_R_AUTH_2 r;
|
||||
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
|
||||
fstring machine_acct;
|
||||
|
||||
prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
|
||||
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 */
|
||||
|
||||
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));
|
||||
|
||||
/* 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,
|
||||
*neg_flags);
|
||||
|
||||
|
@ -1621,9 +1621,6 @@ NTSTATUS cli_nt_setup_netsec(struct cli_state *cli, int sec_chan, int auth_flags
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
if (lp_client_schannel() != False)
|
||||
neg_flags |= NETLOGON_NEG_SCHANNEL;
|
||||
|
||||
neg_flags |= NETLOGON_NEG_SCHANNEL;
|
||||
|
||||
result = cli_nt_setup_creds(cli, sec_chan, trust_password,
|
||||
|
@ -182,6 +182,50 @@ static BOOL net_io_netinfo_2(const char *desc, NETLOGON_INFO_2 *info, prs_struct
|
||||
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.
|
||||
********************************************************************/
|
||||
@ -210,9 +254,23 @@ BOOL net_io_q_logon_ctrl2(const char *desc, NET_Q_LOGON_CTRL2 *q_l, prs_struct *
|
||||
return False;
|
||||
if(!prs_uint32("query_level ", ps, depth, &q_l->query_level))
|
||||
return False;
|
||||
if(!prs_uint32("switch_value ", ps, depth, &q_l->switch_value))
|
||||
return False;
|
||||
switch ( q_l->function_code ) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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->query_level = query_level;
|
||||
q_l->switch_value = 0x01;
|
||||
|
||||
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,
|
||||
const char *trusted_domain_name)
|
||||
{
|
||||
DEBUG(5,("init_r_logon_ctrl2\n"));
|
||||
|
||||
r_l->switch_value = query_level; /* should only be 0x1 */
|
||||
r_l->switch_value = query_level;
|
||||
|
||||
switch (query_level) {
|
||||
case 1:
|
||||
|
@ -227,8 +227,6 @@ static BOOL api_net_trust_dom_list(pipes_struct *p)
|
||||
ZERO_STRUCT(q_u);
|
||||
ZERO_STRUCT(r_u);
|
||||
|
||||
DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
|
||||
|
||||
/* grab the lsa trusted domain list query... */
|
||||
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"));
|
||||
@ -244,8 +242,6 @@ static BOOL api_net_trust_dom_list(pipes_struct *p)
|
||||
return False;
|
||||
}
|
||||
|
||||
DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
@ -263,7 +259,6 @@ static BOOL api_net_logon_ctrl2(pipes_struct *p)
|
||||
ZERO_STRUCT(q_u);
|
||||
ZERO_STRUCT(r_u);
|
||||
|
||||
DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
|
||||
|
||||
/* grab the lsa netlogon ctrl2 query... */
|
||||
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;
|
||||
}
|
||||
|
||||
DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
@ -297,8 +290,6 @@ static BOOL api_net_logon_ctrl(pipes_struct *p)
|
||||
ZERO_STRUCT(q_u);
|
||||
ZERO_STRUCT(r_u);
|
||||
|
||||
DEBUG(6,("api_net_logon_ctrl: %d\n", __LINE__));
|
||||
|
||||
/* grab the lsa netlogon ctrl query... */
|
||||
if(!net_io_q_logon_ctrl("", &q_u, data, 0)) {
|
||||
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;
|
||||
}
|
||||
|
||||
DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
@ -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_LOGON_SERVERS 0x51f
|
||||
#define NO_ERROR 0x0
|
||||
|
||||
/*************************************************************************
|
||||
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 pdc_connection_status = 0x0;
|
||||
uint32 logon_attempts = 0x0;
|
||||
uint32 tc_status = ERROR_NO_LOGON_SERVERS;
|
||||
const char *trusted_domain = "test_domain";
|
||||
uint32 tc_status;
|
||||
fstring servername, domain, dc_name, dc_name2;
|
||||
struct in_addr dc_ip;
|
||||
|
||||
DEBUG(0, ("*** net long ctrl2 %d, %d, %d\n",
|
||||
q_u->function_code, q_u->query_level, q_u->switch_value));
|
||||
/* this should be \\global_myname() */
|
||||
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 */
|
||||
init_net_r_logon_ctrl2(r_u, q_u->query_level,
|
||||
flags, pdc_connection_status, logon_attempts,
|
||||
tc_status, trusted_domain);
|
||||
fstr_sprintf( dc_name, "\\\\%s", dc_name2 );
|
||||
|
||||
tc_status = NO_ERROR;
|
||||
|
||||
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)
|
||||
send_sync_message();
|
||||
|
||||
DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
|
||||
|
||||
return r_u->status;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user