summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2004-06-03 18:00:22 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 10:51:53 -0500
commit9dbf2e2419e2ba0f2293b4a7a5971123f34a09ad (patch)
tree7b126d923a8a0ee8b02ab43bf54a43ce3344f051
parent4e1b26db3490c6063bf0ea05b8ae7e34a96ca8a9 (diff)
downloadsamba-9dbf2e2419e2ba0f2293b4a7a5971123f34a09ad.tar.gz
samba-9dbf2e2419e2ba0f2293b4a7a5971123f34a09ad.tar.bz2
samba-9dbf2e2419e2ba0f2293b4a7a5971123f34a09ad.zip
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 used to be commit e9f109d1b38e0b0adec9b7e9a907f90a79d297ea)
-rw-r--r--source3/auth/auth_util.c4
-rw-r--r--source3/include/rpc_dce.h3
-rw-r--r--source3/include/rpc_netlogon.h42
-rw-r--r--source3/nsswitch/winbindd_cache.c6
-rw-r--r--source3/nsswitch/winbindd_cm.c46
-rw-r--r--source3/rpc_client/cli_netlogon.c11
-rw-r--r--source3/rpc_client/cli_pipe.c3
-rw-r--r--source3/rpc_parse/parse_net.c67
-rw-r--r--source3/rpc_server/srv_netlog.c11
-rw-r--r--source3/rpc_server/srv_netlog_nt.c69
10 files changed, 207 insertions, 55 deletions
diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c
index 9a03e7fe13..e6cc0fe5b3 100644
--- a/source3/auth/auth_util.c
+++ b/source3/auth/auth_util.c
@@ -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);
diff --git a/source3/include/rpc_dce.h b/source3/include/rpc_dce.h
index 0df903109d..57b1184bd9 100644
--- a/source3/include/rpc_dce.h
+++ b/source3/include/rpc_dce.h
@@ -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
{
diff --git a/source3/include/rpc_netlogon.h b/source3/include/rpc_netlogon.h
index a5b93b0238..ad30cfbafb 100644
--- a/source3/include/rpc_netlogon.h
+++ b/source3/include/rpc_netlogon.h
@@ -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;
/*******************************************************
diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c
index 877fa2d995..bbd98a620f 100644
--- a/source3/nsswitch/winbindd_cache.c
+++ b/source3/nsswitch/winbindd_cache.c
@@ -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)) {
diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c
index eda962088d..04f87fc1a2 100644
--- a/source3/nsswitch/winbindd_cm.c
+++ b/source3/nsswitch/winbindd_cm.c
@@ -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)));
diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index f6d88a1950..02d2611d88 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -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);
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index b24dbb7d25..9e2d5aa4a7 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -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,
diff --git a/source3/rpc_parse/parse_net.c b/source3/rpc_parse/parse_net.c
index 36d55c7bf6..b42b9b2a8b 100644
--- a/source3/rpc_parse/parse_net.c
+++ b/source3/rpc_parse/parse_net.c
@@ -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:
diff --git a/source3/rpc_server/srv_netlog.c b/source3/rpc_server/srv_netlog.c
index f06a2002e3..705b629732 100644
--- a/source3/rpc_server/srv_netlog.c
+++ b/source3/rpc_server/srv_netlog.c
@@ -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;
}
diff --git a/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c
index be8eda82c9..264b7a74a7 100644
--- a/source3/rpc_server/srv_netlog_nt.c
+++ b/source3/rpc_server/srv_netlog_nt.c
@@ -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__));
-
-
- /* 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);
+ 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;
+ }
+
+ 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;
}