diff options
author | Gerald Carter <jerry@samba.org> | 2004-06-03 18:00:22 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 10:51:53 -0500 |
commit | 9dbf2e2419e2ba0f2293b4a7a5971123f34a09ad (patch) | |
tree | 7b126d923a8a0ee8b02ab43bf54a43ce3344f051 | |
parent | 4e1b26db3490c6063bf0ea05b8ae7e34a96ca8a9 (diff) | |
download | samba-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.c | 4 | ||||
-rw-r--r-- | source3/include/rpc_dce.h | 3 | ||||
-rw-r--r-- | source3/include/rpc_netlogon.h | 42 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_cache.c | 6 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_cm.c | 46 | ||||
-rw-r--r-- | source3/rpc_client/cli_netlogon.c | 11 | ||||
-rw-r--r-- | source3/rpc_client/cli_pipe.c | 3 | ||||
-rw-r--r-- | source3/rpc_parse/parse_net.c | 67 | ||||
-rw-r--r-- | source3/rpc_server/srv_netlog.c | 11 | ||||
-rw-r--r-- | source3/rpc_server/srv_netlog_nt.c | 69 |
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; } |