From dd320c0924ce393a89b1cab020fd5cffc5b80380 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 12 Dec 2007 18:03:20 +0100 Subject: [PATCH 01/14] Fix for bug #4801: Correctly implement lsa lookup levels for lookupnames. This is a first patch aimed at fixing bug #4801. It is still incomplete in that winbindd does not walk the the trusted domains to lookup unqualified names here. Apart from that this fix should be pretty much complete. Michael --- source/passdb/lookup_sid.c | 45 ++++++++++++++++++++++++---------- source/rpc_server/srv_lsa_nt.c | 37 +++++++++++++++++++++------- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/source/passdb/lookup_sid.c b/source/passdb/lookup_sid.c index bb54959e96b..54db14fbfe8 100644 --- a/source/passdb/lookup_sid.c +++ b/source/passdb/lookup_sid.c @@ -59,16 +59,19 @@ bool lookup_name(TALLOC_CTX *mem_ctx, name = talloc_strdup(tmp_ctx, full_name); } - DEBUG(10,("lookup_name: %s => %s (domain), %s (name)\n", - full_name, domain, name)); - if ((domain == NULL) || (name == NULL)) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(tmp_ctx); return false; } - if (strequal(domain, get_global_sam_name())) { + DEBUG(10,("lookup_name: %s => %s (domain), %s (name)\n", + full_name, domain, name)); + DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags)); + + if ((flags & LOOKUP_NAME_DOMAIN) && + strequal(domain, get_global_sam_name())) + { /* It's our own domain, lookup the name in passdb */ if (lookup_global_sam_name(name, flags, &rid, &type)) { @@ -80,8 +83,9 @@ bool lookup_name(TALLOC_CTX *mem_ctx, return false; } - if (strequal(domain, builtin_domain_name())) { - + if ((flags & LOOKUP_NAME_BUILTIN) && + strequal(domain, builtin_domain_name())) + { /* Explicit request for a name in BUILTIN */ if (lookup_builtin_name(name, &rid)) { sid_copy(&sid, &global_sid_Builtin); @@ -97,6 +101,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, * domain yet at this point yet. This comes later. */ if ((domain[0] != '\0') && + (flags & ~(LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED)) && (winbind_lookup_name(domain, name, &sid, &type))) { goto ok; } @@ -131,14 +136,18 @@ bool lookup_name(TALLOC_CTX *mem_ctx, /* 1. well-known names */ - if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) { + if ((flags & LOOKUP_NAME_WKN) && + lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) + { type = SID_NAME_WKN_GRP; goto ok; } /* 2. Builtin domain as such */ - if (strequal(name, builtin_domain_name())) { + if ((flags & (LOOKUP_NAME_BUILTIN|LOOKUP_NAME_REMOTE)) && + strequal(name, builtin_domain_name())) + { /* Swap domain and name */ tmp = name; name = domain; domain = tmp; sid_copy(&sid, &global_sid_Builtin); @@ -148,7 +157,9 @@ bool lookup_name(TALLOC_CTX *mem_ctx, /* 3. Account domain */ - if (strequal(name, get_global_sam_name())) { + if ((flags & LOOKUP_NAME_DOMAIN) && + strequal(name, get_global_sam_name())) + { if (!secrets_fetch_domain_sid(name, &sid)) { DEBUG(3, ("Could not fetch my SID\n")); TALLOC_FREE(tmp_ctx); @@ -162,7 +173,9 @@ bool lookup_name(TALLOC_CTX *mem_ctx, /* 4. Primary domain */ - if (!IS_DC && strequal(name, lp_workgroup())) { + if ((flags & LOOKUP_NAME_DOMAIN) && !IS_DC && + strequal(name, lp_workgroup())) + { if (!secrets_fetch_domain_sid(name, &sid)) { DEBUG(3, ("Could not fetch the domain SID\n")); TALLOC_FREE(tmp_ctx); @@ -177,7 +190,9 @@ bool lookup_name(TALLOC_CTX *mem_ctx, /* 5. Trusted domains as such, to me it looks as if members don't do this, tested an XP workstation in a NT domain -- vl */ - if (IS_DC && (pdb_get_trusteddom_pw(name, NULL, &sid, NULL))) { + if ((flags & LOOKUP_NAME_REMOTE) && IS_DC && + (secrets_fetch_trusted_domain_password(name, NULL, &sid, NULL))) + { /* Swap domain and name */ tmp = name; name = domain; domain = tmp; type = SID_NAME_DOMAIN; @@ -186,7 +201,9 @@ bool lookup_name(TALLOC_CTX *mem_ctx, /* 6. Builtin aliases */ - if (lookup_builtin_name(name, &rid)) { + if ((flags & LOOKUP_NAME_BUILTIN) && + lookup_builtin_name(name, &rid)) + { domain = talloc_strdup(tmp_ctx, builtin_domain_name()); sid_copy(&sid, &global_sid_Builtin); sid_append_rid(&sid, rid); @@ -199,7 +216,9 @@ bool lookup_name(TALLOC_CTX *mem_ctx, /* Both cases are done by looking at our passdb */ - if (lookup_global_sam_name(name, flags, &rid, &type)) { + if ((flags & LOOKUP_NAME_DOMAIN) && + lookup_global_sam_name(name, flags, &rid, &type)) + { domain = talloc_strdup(tmp_ctx, get_global_sam_name()); sid_copy(&sid, get_global_sam_sid()); sid_append_rid(&sid, rid); diff --git a/source/rpc_server/srv_lsa_nt.c b/source/rpc_server/srv_lsa_nt.c index 20655082a51..c5f0c7b6ab1 100644 --- a/source/rpc_server/srv_lsa_nt.c +++ b/source/rpc_server/srv_lsa_nt.c @@ -1035,6 +1035,31 @@ NTSTATUS _lsa_lookup_sids3(pipes_struct *p, return r_u->status; } +static int lsa_lookup_level_to_flags(uint16 level) +{ + int flags; + + switch (level) { + case 1: + flags = LOOKUP_NAME_ALL; + break; + case 2: + flags = LOOKUP_NAME_DOMAIN|LOOKUP_NAME_REMOTE|LOOKUP_NAME_ISOLATED; + break; + case 3: + flags = LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED; + break; + case 4: + case 5: + case 6: + default: + flags = LOOKUP_NAME_NONE; + break; + } + + return flags; +} + /*************************************************************************** lsa_reply_lookup_names ***************************************************************************/ @@ -1054,10 +1079,7 @@ NTSTATUS _lsa_lookup_names(pipes_struct *p,LSA_Q_LOOKUP_NAMES *q_u, LSA_R_LOOKUP DEBUG(5,("_lsa_lookup_names: truncating name lookup list to %d\n", num_entries)); } - /* Probably the lookup_level is some sort of bitmask. */ - if (q_u->lookup_level == 1) { - flags = LOOKUP_NAME_ALL; - } + flags = lsa_lookup_level_to_flags(q_u->lookup_level); ref = TALLOC_ZERO_P(p->mem_ctx, DOM_R_REF); if (!ref) { @@ -1123,11 +1145,8 @@ NTSTATUS _lsa_lookup_names2(pipes_struct *p, LSA_Q_LOOKUP_NAMES2 *q_u, LSA_R_LOO num_entries = MAX_LOOKUP_SIDS; DEBUG(5,("_lsa_lookup_names2: truncating name lookup list to %d\n", num_entries)); } - - /* Probably the lookup_level is some sort of bitmask. */ - if (q_u->lookup_level == 1) { - flags = LOOKUP_NAME_ALL; - } + + flags = lsa_lookup_level_to_flags(q_u->lookup_level); ref = TALLOC_ZERO_P(p->mem_ctx, DOM_R_REF); if (ref == NULL) { From 4788fe392427901f6b1c505e3a743136ac8a91ca Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Mon, 10 Dec 2007 23:53:55 +0100 Subject: [PATCH 02/14] Remove two unneeded functions. secrets_store_trust_account_password() and trust_password_delete() are the write access functions to the SECRETS/$MACHINE.ACC/domain keys in secrets.tdb, the md4 hashed machine passwords. These are not used any more: Current code always writes the clear text password. Michael --- source/passdb/secrets.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/source/passdb/secrets.c b/source/passdb/secrets.c index a4cb76602a8..3466f24533c 100644 --- a/source/passdb/secrets.c +++ b/source/passdb/secrets.c @@ -558,20 +558,6 @@ bool secrets_fetch_trusted_domain_password(const char *domain, char** pwd, return True; } -/************************************************************************ - Routine to set the trust account password for a domain. -************************************************************************/ - -bool secrets_store_trust_account_password(const char *domain, uint8 new_pwd[16]) -{ - struct machine_acct_pass pass; - - pass.mod_time = time(NULL); - memcpy(pass.hash, new_pwd, 16); - - return secrets_store(trust_keystr(domain), (void *)&pass, sizeof(pass)); -} - /** * Routine to store the password for trusted domain * @@ -721,15 +707,6 @@ char *secrets_fetch_machine_password(const char *domain, return ret; } -/************************************************************************ - Routine to delete the machine trust account password file for a domain. -************************************************************************/ - -bool trust_password_delete(const char *domain) -{ - return secrets_delete(trust_keystr(domain)); -} - /************************************************************************ Routine to delete the password for trusted domain ************************************************************************/ From 164bfb25d7b5cfeffeb4d81958b7629a11ca5d5e Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 11 Dec 2007 08:52:20 +0100 Subject: [PATCH 03/14] In cm_prepare_connection(), only get auth user creds if we need to. Michael --- source/winbindd/winbindd_cm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/winbindd/winbindd_cm.c b/source/winbindd/winbindd_cm.c index 3f6544965d0..0a96e04052c 100644 --- a/source/winbindd/winbindd_cm.c +++ b/source/winbindd/winbindd_cm.c @@ -676,8 +676,6 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, return NT_STATUS_NO_MEMORY; } - cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password); - *retry = True; got_mutex = secrets_named_mutex(controller, @@ -795,6 +793,8 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, (*cli)->use_kerberos = False; + cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password); + if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) && (strlen(ipc_username) > 0)) { From cdc60d8ae8c0ef804206b20b451e9557f97d4439 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 11 Dec 2007 12:47:28 +0100 Subject: [PATCH 04/14] Streamline logic in cm_connect_netlogon() by retrieving trust password only, when it will be used. Michael --- source/winbindd/winbindd_cm.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/source/winbindd/winbindd_cm.c b/source/winbindd/winbindd_cm.c index 0a96e04052c..d5c8b9955f2 100644 --- a/source/winbindd/winbindd_cm.c +++ b/source/winbindd/winbindd_cm.c @@ -2219,10 +2219,6 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain, return NT_STATUS_OK; } - if ((IS_DC || domain->primary) && !get_trust_pw(domain->name, mach_pwd, &sec_chan_type)) { - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - } - netlogon_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_NETLOGON, &result); if (netlogon_pipe == NULL) { @@ -2234,11 +2230,16 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain, neg_flags &= ~NETLOGON_NEG_SCHANNEL; goto no_schannel; } - + if (lp_client_schannel() != False) { neg_flags |= NETLOGON_NEG_SCHANNEL; } + if (!get_trust_pw(domain->name, mach_pwd, &sec_chan_type)) { + cli_rpc_pipe_close(netlogon_pipe); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + /* if we are a DC and this is a trusted domain, then we need to use our domain name in the net_req_auth2() request */ From 6ced4a7f88798dc449a667d63bc29bf6c569291f Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 11 Dec 2007 13:05:44 +0100 Subject: [PATCH 05/14] Let get_trust_pw() determine the machine_account_name to use. Up to now each caller used its own logic. This eliminates code paths where there was a special treatment of the following situation: the domain given is not our workgroup (i.e. our own domain) and we are not a DC (i.e. it is not a typical trusted domain situation). In situation the given domain name was previously used as the machine account name, resulting in an account name of DOMAIN\\DOMAIN$, which does not seem very reasonable to me. get_trust_pw would not have obtained a password in this situation anyways. I hope I have not missed an important point here! Michael --- source/auth/auth_domain.c | 7 +++++-- source/passdb/passdb.c | 16 +++++++++++++-- source/rpc_client/cli_pipe.c | 38 ++++++----------------------------- source/winbindd/winbindd_cm.c | 22 +++----------------- 4 files changed, 28 insertions(+), 55 deletions(-) diff --git a/source/auth/auth_domain.c b/source/auth/auth_domain.c index 7cddabbbbd0..b428723a061 100644 --- a/source/auth/auth_domain.c +++ b/source/auth/auth_domain.c @@ -127,8 +127,11 @@ machine %s. Error was : %s.\n", dc_name, nt_errstr(result))); uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS; uint32 sec_chan_type = 0; unsigned char machine_pwd[16]; + const char *account_name; - if (!get_trust_pw(domain, machine_pwd, &sec_chan_type)) { + if (!get_trust_pw(domain, machine_pwd, &account_name, + &sec_chan_type)) + { DEBUG(0, ("connect_to_domain_password_server: could not fetch " "trust account password for domain '%s'\n", domain)); @@ -142,7 +145,7 @@ machine %s. Error was : %s.\n", dc_name, nt_errstr(result))); dc_name, /* server name */ domain, /* domain */ global_myname(), /* client name */ - global_myname(), /* machine account name */ + account_name, /* machine account name */ machine_pwd, sec_chan_type, &neg_flags); diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c index 2a4d4c4a0ad..f9b972da9b0 100644 --- a/source/passdb/passdb.c +++ b/source/passdb/passdb.c @@ -1523,10 +1523,12 @@ bool pdb_increment_bad_password_count(struct samu *sampass) /******************************************************************* - Wrapper around retrieving the trust account password + Wrapper around retrieving the trust account password. + appropriate account name is stored in account_name. *******************************************************************/ -bool get_trust_pw(const char *domain, uint8 ret_pwd[16], uint32 *channel) +bool get_trust_pw(const char *domain, uint8 ret_pwd[16], + const char **account_name, uint32 *channel) { DOM_SID sid; char *pwd; @@ -1550,6 +1552,10 @@ bool get_trust_pw(const char *domain, uint8 ret_pwd[16], uint32 *channel) E_md4hash(pwd, ret_pwd); SAFE_FREE(pwd); + if (account_name != NULL) { + *account_name = lp_workgroup(); + } + return True; } @@ -1558,7 +1564,13 @@ bool get_trust_pw(const char *domain, uint8 ret_pwd[16], uint32 *channel) if (secrets_fetch_trust_account_password(domain, ret_pwd, &last_set_time, channel)) + { + if (account_name != NULL) { + *account_name = global_myname(); + } + return True; + } DEBUG(5, ("get_trust_pw: could not fetch trust account " "password for domain %s\n", domain)); diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c index 37558a7ff00..bf019c89a18 100644 --- a/source/rpc_client/cli_pipe.c +++ b/source/rpc_client/cli_pipe.c @@ -2436,7 +2436,7 @@ struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli, struct rpc_pipe_client *netlogon_pipe = NULL; uint32 sec_chan_type = 0; unsigned char machine_pwd[16]; - fstring machine_account; + const char *machine_account; netlogon_pipe = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON, perr); if (!netlogon_pipe) { @@ -2444,7 +2444,8 @@ struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli, } /* Get the machine account credentials from secrets.tdb. */ - if (!get_trust_pw(domain, machine_pwd, &sec_chan_type)) { + if (!get_trust_pw(domain, machine_pwd, &machine_account, &sec_chan_type)) + { DEBUG(0, ("get_schannel_session_key: could not fetch " "trust account password for domain '%s'\n", domain)); @@ -2453,20 +2454,6 @@ struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli, return NULL; } - /* A DC should use DOMAIN$ as its account name. - A member server can only use it's machine name since it - does not have an account in a trusted domain. - - We don't check the domain against lp_workgroup() here since - 'net ads join' has to continue to work with only the realm - specified in smb.conf. -- jerry */ - - if ( IS_DC && !strequal(domain, lp_workgroup()) && lp_allow_trusted_domains()) { - fstrcpy( machine_account, lp_workgroup() ); - } else { - fstrcpy(machine_account, global_myname()); - } - *perr = rpccli_netlogon_setup_creds(netlogon_pipe, cli->desthost, /* server name */ domain, /* domain */ @@ -2562,7 +2549,7 @@ static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_ struct rpc_pipe_client *netlogon_pipe = NULL; uint32 sec_chan_type = 0; unsigned char machine_pwd[16]; - fstring machine_account; + const char *machine_account; netlogon_pipe = cli_rpc_pipe_open_spnego_ntlmssp(cli, PI_NETLOGON, PIPE_AUTH_LEVEL_PRIVACY, domain, username, password, perr); if (!netlogon_pipe) { @@ -2570,7 +2557,8 @@ static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_ } /* Get the machine account credentials from secrets.tdb. */ - if (!get_trust_pw(domain, machine_pwd, &sec_chan_type)) { + if (!get_trust_pw(domain, machine_pwd, &machine_account, &sec_chan_type)) + { DEBUG(0, ("get_schannel_session_key_auth_ntlmssp: could not fetch " "trust account password for domain '%s'\n", domain)); @@ -2579,20 +2567,6 @@ static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_ return NULL; } - /* if we are a DC and this is a trusted domain, then we need to use our - domain name in the net_req_auth2() request */ - - if ( IS_DC && !strequal(domain, lp_workgroup()) && lp_allow_trusted_domains()) { - fstrcpy( machine_account, lp_workgroup() ); - } else { - /* Hmmm. Is this correct for trusted domains when we're a member server ? JRA. */ - if (strequal(domain, lp_workgroup())) { - fstrcpy(machine_account, global_myname()); - } else { - fstrcpy(machine_account, domain); - } - } - *perr = rpccli_netlogon_setup_creds(netlogon_pipe, cli->desthost, /* server name */ domain, /* domain */ diff --git a/source/winbindd/winbindd_cm.c b/source/winbindd/winbindd_cm.c index d5c8b9955f2..adb9d11edca 100644 --- a/source/winbindd/winbindd_cm.c +++ b/source/winbindd/winbindd_cm.c @@ -2235,29 +2235,13 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain, neg_flags |= NETLOGON_NEG_SCHANNEL; } - if (!get_trust_pw(domain->name, mach_pwd, &sec_chan_type)) { + if (!get_trust_pw(domain->name, mach_pwd, &account_name, + &sec_chan_type)) + { cli_rpc_pipe_close(netlogon_pipe); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } - /* if we are a DC and this is a trusted domain, then we need to use our - domain name in the net_req_auth2() request */ - - if ( IS_DC - && !strequal(domain->name, lp_workgroup()) - && lp_allow_trusted_domains() ) - { - account_name = lp_workgroup(); - } else { - account_name = domain->primary ? - global_myname() : domain->name; - } - - if (account_name == NULL) { - cli_rpc_pipe_close(netlogon_pipe); - return NT_STATUS_NO_MEMORY; - } - result = rpccli_netlogon_setup_creds( netlogon_pipe, domain->dcname, /* server name. */ From 91da12b751b3168dc40049f3e90c10d840393efc Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 11 Dec 2007 14:02:45 +0100 Subject: [PATCH 06/14] Refactor the lagacy part of secrets_fetch_trust_account_password() out into a new function secrets_fetch_trust_account_password_legacy() that does only try to obtain the hashed version of the machine password directly from secrets.tdb. Michael --- source/passdb/secrets.c | 44 +++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/source/passdb/secrets.c b/source/passdb/secrets.c index 3466f24533c..fde7fc0968d 100644 --- a/source/passdb/secrets.c +++ b/source/passdb/secrets.c @@ -284,27 +284,19 @@ uint32 get_default_sec_channel(void) /************************************************************************ Routine to get the trust account password for a domain. + This only tries to get the legacy hashed version of the password. The user of this function must have locked the trust password file using the above secrets_lock_trust_account_password(). ************************************************************************/ -bool secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16], - time_t *pass_last_set_time, - uint32 *channel) +bool secrets_fetch_trust_account_password_legacy(const char *domain, + uint8 ret_pwd[16], + time_t *pass_last_set_time, + uint32 *channel) { struct machine_acct_pass *pass; - char *plaintext; size_t size = 0; - plaintext = secrets_fetch_machine_password(domain, pass_last_set_time, - channel); - if (plaintext) { - DEBUG(4,("Using cleartext machine password\n")); - E_md4hash(plaintext, ret_pwd); - SAFE_FREE(plaintext); - return True; - } - if (!(pass = (struct machine_acct_pass *)secrets_fetch( trust_keystr(domain), &size))) { DEBUG(5, ("secrets_fetch failed!\n")); @@ -337,6 +329,32 @@ bool secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16], return True; } +/************************************************************************ + Routine to get the trust account password for a domain. + The user of this function must have locked the trust password file using + the above secrets_lock_trust_account_password(). +************************************************************************/ + +bool secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16], + time_t *pass_last_set_time, + uint32 *channel) +{ + char *plaintext; + + plaintext = secrets_fetch_machine_password(domain, pass_last_set_time, + channel); + if (plaintext) { + DEBUG(4,("Using cleartext machine password\n")); + E_md4hash(plaintext, ret_pwd); + SAFE_FREE(plaintext); + return True; + } + + return secrets_fetch_trust_account_password_legacy(domain, ret_pwd, + pass_last_set_time, + channel); +} + /** * Pack SID passed by pointer * From 4562342eb84e6fdcec15d8b7ae83aa146aabe2b7 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 11 Dec 2007 13:59:54 +0100 Subject: [PATCH 07/14] Export logic of get_trust_pw() to new function get_trust_pw_clear(). get_trust_pw() just now computes the md4 hash of the result of get_trust_pw_clear() if that was successful. As a last resort, in the non-trusted-domain-situation, get_trust_pw() now tries to directly obtain the hashed version of the password out of secrets.tdb. Michael --- source/passdb/passdb.c | 100 +++++++++++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 29 deletions(-) diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c index f9b972da9b0..488458fc857 100644 --- a/source/passdb/passdb.c +++ b/source/passdb/passdb.c @@ -1521,6 +1521,66 @@ bool pdb_increment_bad_password_count(struct samu *sampass) return True; } +bool is_trusted_domain_situation(const char *domain_name) +{ + return IS_DC && + lp_allow_trusted_domains() && + !strequal(domain_name, lp_workgroup()); +} + +/******************************************************************* + Wrapper around retrieving the clear text trust account password. + appropriate account name is stored in account_name. + Caller must free password, but not account_name. +*******************************************************************/ + +bool get_trust_pw_clear(const char *domain, char **ret_pwd, + const char **account_name, uint32 *channel) +{ + DOM_SID sid; + char *pwd; + time_t last_set_time; + + /* if we are a DC and this is not our domain, then lookup an account + * for the domain trust */ + + if (is_trusted_domain_situation(domain)) { + if (!pdb_get_trusteddom_pw(domain, ret_pwd, &sid, + &last_set_time)) + { + DEBUG(0, ("get_trust_pw: could not fetch trust " + "account password for trusted domain %s\n", + domain)); + return false; + } + + *channel = SEC_CHAN_DOMAIN; + + if (account_name != NULL) { + *account_name = lp_workgroup(); + } + + return true; + } + + /* Just get the account for the requested domain. In the future this + * might also cover to be member of more than one domain. */ + + pwd = secrets_fetch_machine_password(domain, &last_set_time, channel); + + if (pwd != NULL) { + *ret_pwd = pwd; + if (account_name != NULL) { + *account_name = global_myname(); + } + + return true; + } + + DEBUG(5, ("get_trust_pw_clear: could not fetch clear text trust " + "account password for domain %s\n", domain)); + return false; +} /******************************************************************* Wrapper around retrieving the trust account password. @@ -1530,49 +1590,31 @@ bool pdb_increment_bad_password_count(struct samu *sampass) bool get_trust_pw(const char *domain, uint8 ret_pwd[16], const char **account_name, uint32 *channel) { - DOM_SID sid; - char *pwd; + char *pwd = NULL; time_t last_set_time; - /* if we are a DC and this is not our domain, then lookup an account - for the domain trust */ - - if (IS_DC && !strequal(domain, lp_workgroup()) && - lp_allow_trusted_domains()) - { - if (!pdb_get_trusteddom_pw(domain, &pwd, &sid, &last_set_time)) - { - DEBUG(0, ("get_trust_pw: could not fetch trust " - "account password for trusted domain %s\n", - domain)); - return False; - } - - *channel = SEC_CHAN_DOMAIN; + if (get_trust_pw_clear(domain, &pwd, account_name, channel)) { E_md4hash(pwd, ret_pwd); SAFE_FREE(pwd); - - if (account_name != NULL) { - *account_name = lp_workgroup(); - } - - return True; + return true; + } else if (is_trusted_domain_situation(domain)) { + return false; } - /* Just get the account for the requested domain. In the future this - * might also cover to be member of more than one domain. */ + /* as a fallback, try to get the hashed pwd directly from the tdb... */ - if (secrets_fetch_trust_account_password(domain, ret_pwd, - &last_set_time, channel)) + if (secrets_fetch_trust_account_password_legacy(domain, ret_pwd, + &last_set_time, + channel)) { if (account_name != NULL) { *account_name = global_myname(); } - return True; + return true; } - DEBUG(5, ("get_trust_pw: could not fetch trust account " + DEBUG(5, ("get_trust_pw_hash: could not fetch trust account " "password for domain %s\n", domain)); return False; } From 0cde7ac9cb39a0026a38ccf66dbecefc12931074 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 11 Dec 2007 14:07:32 +0100 Subject: [PATCH 08/14] Rename get_trust_pw() to get_trust_pw_hash(). Michael --- source/auth/auth_domain.c | 4 ++-- source/passdb/passdb.c | 4 ++-- source/rpc_client/cli_pipe.c | 6 ++++-- source/winbindd/winbindd_cm.c | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/source/auth/auth_domain.c b/source/auth/auth_domain.c index b428723a061..b2c87174fd3 100644 --- a/source/auth/auth_domain.c +++ b/source/auth/auth_domain.c @@ -129,8 +129,8 @@ machine %s. Error was : %s.\n", dc_name, nt_errstr(result))); unsigned char machine_pwd[16]; const char *account_name; - if (!get_trust_pw(domain, machine_pwd, &account_name, - &sec_chan_type)) + if (!get_trust_pw_hash(domain, machine_pwd, &account_name, + &sec_chan_type)) { DEBUG(0, ("connect_to_domain_password_server: could not fetch " "trust account password for domain '%s'\n", diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c index 488458fc857..11c5b681970 100644 --- a/source/passdb/passdb.c +++ b/source/passdb/passdb.c @@ -1587,8 +1587,8 @@ bool get_trust_pw_clear(const char *domain, char **ret_pwd, appropriate account name is stored in account_name. *******************************************************************/ -bool get_trust_pw(const char *domain, uint8 ret_pwd[16], - const char **account_name, uint32 *channel) +bool get_trust_pw_hash(const char *domain, uint8 ret_pwd[16], + const char **account_name, uint32 *channel) { char *pwd = NULL; time_t last_set_time; diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c index bf019c89a18..9f1d9c6e3e6 100644 --- a/source/rpc_client/cli_pipe.c +++ b/source/rpc_client/cli_pipe.c @@ -2444,7 +2444,8 @@ struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli, } /* Get the machine account credentials from secrets.tdb. */ - if (!get_trust_pw(domain, machine_pwd, &machine_account, &sec_chan_type)) + if (!get_trust_pw_hash(domain, machine_pwd, &machine_account, + &sec_chan_type)) { DEBUG(0, ("get_schannel_session_key: could not fetch " "trust account password for domain '%s'\n", @@ -2557,7 +2558,8 @@ static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_ } /* Get the machine account credentials from secrets.tdb. */ - if (!get_trust_pw(domain, machine_pwd, &machine_account, &sec_chan_type)) + if (!get_trust_pw_hash(domain, machine_pwd, &machine_account, + &sec_chan_type)) { DEBUG(0, ("get_schannel_session_key_auth_ntlmssp: could not fetch " "trust account password for domain '%s'\n", diff --git a/source/winbindd/winbindd_cm.c b/source/winbindd/winbindd_cm.c index adb9d11edca..d8040d79acf 100644 --- a/source/winbindd/winbindd_cm.c +++ b/source/winbindd/winbindd_cm.c @@ -2235,8 +2235,8 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain, neg_flags |= NETLOGON_NEG_SCHANNEL; } - if (!get_trust_pw(domain->name, mach_pwd, &account_name, - &sec_chan_type)) + if (!get_trust_pw_hash(domain->name, mach_pwd, &account_name, + &sec_chan_type)) { cli_rpc_pipe_close(netlogon_pipe); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; From b2e12365b56f24586a7dfcb845f4de51f0b0e7d5 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 11 Dec 2007 14:12:49 +0100 Subject: [PATCH 09/14] Pass NULL instead of unneeded &sid: pdb_get_trusteddom_pw() checks. Michael --- source/passdb/passdb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c index 11c5b681970..c4248bb48ed 100644 --- a/source/passdb/passdb.c +++ b/source/passdb/passdb.c @@ -1537,7 +1537,6 @@ bool is_trusted_domain_situation(const char *domain_name) bool get_trust_pw_clear(const char *domain, char **ret_pwd, const char **account_name, uint32 *channel) { - DOM_SID sid; char *pwd; time_t last_set_time; @@ -1545,7 +1544,7 @@ bool get_trust_pw_clear(const char *domain, char **ret_pwd, * for the domain trust */ if (is_trusted_domain_situation(domain)) { - if (!pdb_get_trusteddom_pw(domain, ret_pwd, &sid, + if (!pdb_get_trusteddom_pw(domain, ret_pwd, NULL, &last_set_time)) { DEBUG(0, ("get_trust_pw: could not fetch trust " From e77c4022cfbb868e608edcb06b676658b0e201ad Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 11 Dec 2007 14:36:11 +0100 Subject: [PATCH 10/14] Refactoring out get_schannel_session_key logic. Refactor the actual retrieval of the session key through the established netlogon pipe out of get_schannel_session_key() and get_schannel_session_key_auth_ntlmssp() into a new function get_schannel_session_key_common(). (To avoid code duplication.) Michael --- source/rpc_client/cli_pipe.c | 92 +++++++++++++++--------------------- 1 file changed, 39 insertions(+), 53 deletions(-) diff --git a/source/rpc_client/cli_pipe.c b/source/rpc_client/cli_pipe.c index 9f1d9c6e3e6..f61ea95d042 100644 --- a/source/rpc_client/cli_pipe.c +++ b/source/rpc_client/cli_pipe.c @@ -2424,25 +2424,18 @@ struct rpc_pipe_client *cli_rpc_pipe_open_spnego_ntlmssp(struct cli_state *cli, } /**************************************************************************** - Open a netlogon pipe and get the schannel session key. - Now exposed to external callers. + Get a the schannel session key out of an already opened netlogon pipe. ****************************************************************************/ - -struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli, - const char *domain, - uint32 *pneg_flags, - NTSTATUS *perr) +static bool get_schannel_session_key_common(struct rpc_pipe_client *netlogon_pipe, + struct cli_state *cli, + const char *domain, + uint32 *pneg_flags, + NTSTATUS *perr) { - struct rpc_pipe_client *netlogon_pipe = NULL; uint32 sec_chan_type = 0; unsigned char machine_pwd[16]; const char *machine_account; - netlogon_pipe = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON, perr); - if (!netlogon_pipe) { - return NULL; - } - /* Get the machine account credentials from secrets.tdb. */ if (!get_trust_pw_hash(domain, machine_pwd, &machine_account, &sec_chan_type)) @@ -2450,9 +2443,8 @@ struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli, DEBUG(0, ("get_schannel_session_key: could not fetch " "trust account password for domain '%s'\n", domain)); - cli_rpc_pipe_close(netlogon_pipe); *perr = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - return NULL; + return false; } *perr = rpccli_netlogon_setup_creds(netlogon_pipe, @@ -2465,11 +2457,10 @@ struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli, pneg_flags); if (!NT_STATUS_IS_OK(*perr)) { - DEBUG(3,("get_schannel_session_key: rpccli_netlogon_setup_creds " + DEBUG(3,("get_schannel_session_key_common: rpccli_netlogon_setup_creds " "failed with result %s to server %s, domain %s, machine account %s.\n", nt_errstr(*perr), cli->desthost, domain, machine_account )); - cli_rpc_pipe_close(netlogon_pipe); - return NULL; + return false; } if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) { @@ -2477,6 +2468,34 @@ struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli, cli->desthost)); cli_rpc_pipe_close(netlogon_pipe); *perr = NT_STATUS_INVALID_NETWORK_RESPONSE; + return false; + } + + return true; +} + +/**************************************************************************** + Open a netlogon pipe and get the schannel session key. + Now exposed to external callers. + ****************************************************************************/ + + +struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli, + const char *domain, + uint32 *pneg_flags, + NTSTATUS *perr) +{ + struct rpc_pipe_client *netlogon_pipe = NULL; + + netlogon_pipe = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON, perr); + if (!netlogon_pipe) { + return NULL; + } + + if (!get_schannel_session_key_common(netlogon_pipe, cli, domain, + pneg_flags, perr)) + { + cli_rpc_pipe_close(netlogon_pipe); return NULL; } @@ -2548,49 +2567,16 @@ static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_ NTSTATUS *perr) { struct rpc_pipe_client *netlogon_pipe = NULL; - uint32 sec_chan_type = 0; - unsigned char machine_pwd[16]; - const char *machine_account; netlogon_pipe = cli_rpc_pipe_open_spnego_ntlmssp(cli, PI_NETLOGON, PIPE_AUTH_LEVEL_PRIVACY, domain, username, password, perr); if (!netlogon_pipe) { return NULL; } - /* Get the machine account credentials from secrets.tdb. */ - if (!get_trust_pw_hash(domain, machine_pwd, &machine_account, - &sec_chan_type)) + if (!get_schannel_session_key_common(netlogon_pipe, cli, domain, + pneg_flags, perr)) { - DEBUG(0, ("get_schannel_session_key_auth_ntlmssp: could not fetch " - "trust account password for domain '%s'\n", - domain)); cli_rpc_pipe_close(netlogon_pipe); - *perr = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - return NULL; - } - - *perr = rpccli_netlogon_setup_creds(netlogon_pipe, - cli->desthost, /* server name */ - domain, /* domain */ - global_myname(), /* client name */ - machine_account, /* machine account name */ - machine_pwd, - sec_chan_type, - pneg_flags); - - if (!NT_STATUS_IS_OK(*perr)) { - DEBUG(3,("get_schannel_session_key_auth_ntlmssp: rpccli_netlogon_setup_creds " - "failed with result %s\n", - nt_errstr(*perr) )); - cli_rpc_pipe_close(netlogon_pipe); - return NULL; - } - - if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) { - DEBUG(3, ("get_schannel_session_key_auth_ntlmssp: Server %s did not offer schannel\n", - cli->desthost)); - cli_rpc_pipe_close(netlogon_pipe); - *perr = NT_STATUS_INVALID_NETWORK_RESPONSE; return NULL; } From 18c66a364e0ddc4960769871ca190944f7fe5c44 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 11 Dec 2007 15:39:36 +0100 Subject: [PATCH 11/14] Streamline and fix logic of cm_prepare_connection(). Do not attempt to do a session setup when in a trusted domain situation (this gives STATUS_NOLOGON_TRUSTED_DOMAIN_ACCOUNT). Use get_trust_pw_clear to get machine trust account. Only call this when the results is really used. Use the proper domain and account name for session setup. Michael --- source/winbindd/winbindd_cm.c | 62 +++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/source/winbindd/winbindd_cm.c b/source/winbindd/winbindd_cm.c index d8040d79acf..00d9092dc3d 100644 --- a/source/winbindd/winbindd_cm.c +++ b/source/winbindd/winbindd_cm.c @@ -646,8 +646,13 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, struct cli_state **cli, bool *retry) { - char *machine_password, *machine_krb5_principal, *machine_account; - char *ipc_username, *ipc_domain, *ipc_password; + char *machine_password = NULL; + char *machine_krb5_principal = NULL; + char *machine_account = NULL; + const char *account_name = NULL; + char *ipc_username = NULL; + char *ipc_domain = NULL; + char *ipc_password = NULL; bool got_mutex; @@ -661,21 +666,6 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, DEBUG(10,("cm_prepare_connection: connecting to DC %s for domain %s\n", controller, domain->name )); - machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, - NULL); - - if (asprintf(&machine_account, "%s$", global_myname()) == -1) { - SAFE_FREE(machine_password); - return NT_STATUS_NO_MEMORY; - } - - if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), - lp_realm()) == -1) { - SAFE_FREE(machine_account); - SAFE_FREE(machine_password); - return NT_STATUS_NO_MEMORY; - } - *retry = True; got_mutex = secrets_named_mutex(controller, @@ -732,10 +722,32 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, result = NT_STATUS_UNSUCCESSFUL; goto done; } - - if ((*cli)->protocol >= PROTOCOL_NT1 && (*cli)->capabilities & CAP_EXTENDED_SECURITY) { + + if (!is_trusted_domain_situation(domain->name) && + (*cli)->protocol >= PROTOCOL_NT1 && + (*cli)->capabilities & CAP_EXTENDED_SECURITY) + { ADS_STATUS ads_status; + if (!get_trust_pw_clear(domain->name, &machine_password, + &account_name, NULL)) + { + result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + goto done; + } + + if (asprintf(&machine_account, "%s$", account_name) == -1) { + result = NT_STATUS_NO_MEMORY; + goto done; + } + + if (asprintf(&machine_krb5_principal, "%s$@%s", account_name, + lp_realm()) == -1) + { + result = NT_STATUS_NO_MEMORY; + goto done; + } + if (lp_security() == SEC_ADS) { /* Try a krb5 session */ @@ -750,7 +762,7 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, ads_status = cli_session_setup_spnego(*cli, machine_krb5_principal, machine_password, - lp_workgroup()); + domain->name); if (!ADS_ERR_OK(ads_status)) { DEBUG(4,("failed kerberos session setup with %s\n", @@ -760,7 +772,7 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, result = ads_ntstatus(ads_status); if (NT_STATUS_IS_OK(result)) { /* Ensure creds are stored for NTLMSSP authenticated pipe access. */ - cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password); + cli_init_creds(*cli, machine_account, domain->name, machine_password); goto session_setup_done; } } @@ -770,12 +782,12 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, DEBUG(5, ("connecting to %s from %s with username " "[%s]\\[%s]\n", controller, global_myname(), - lp_workgroup(), machine_account)); + domain->name, machine_account)); ads_status = cli_session_setup_spnego(*cli, machine_account, machine_password, - lp_workgroup()); + domain->name); if (!ADS_ERR_OK(ads_status)) { DEBUG(4, ("authenticated session setup failed with %s\n", ads_errstr(ads_status))); @@ -784,12 +796,12 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, result = ads_ntstatus(ads_status); if (NT_STATUS_IS_OK(result)) { /* Ensure creds are stored for NTLMSSP authenticated pipe access. */ - cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password); + cli_init_creds(*cli, machine_account, domain->name, machine_password); goto session_setup_done; } } - /* Fall back to non-kerberos session setup */ + /* Fall back to non-kerberos session setup with auth_user */ (*cli)->use_kerberos = False; From 481f18b20d6d5ee12c62120a3559bb16cc98e465 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 11 Dec 2007 16:32:38 +0100 Subject: [PATCH 12/14] Refactor out assembling of trust creds (pw, account name, principal). Michael --- source/winbindd/winbindd_cm.c | 55 ++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/source/winbindd/winbindd_cm.c b/source/winbindd/winbindd_cm.c index 00d9092dc3d..cc7a0cc6714 100644 --- a/source/winbindd/winbindd_cm.c +++ b/source/winbindd/winbindd_cm.c @@ -635,6 +635,40 @@ static bool get_dc_name_via_netlogon(const struct winbindd_domain *domain, return True; } +/** + * Helper function to assemble trust password and account name + */ +static NTSTATUS get_trust_creds(const struct winbindd_domain *domain, + char **machine_password, + char **machine_account, + char **machine_krb5_principal) +{ + const char *account_name; + + if (!get_trust_pw_clear(domain->name, machine_password, + &account_name, NULL)) + { + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + + if ((machine_account != NULL) && + (asprintf(machine_account, "%s$", account_name) == -1)) + { + return NT_STATUS_NO_MEMORY; + } + + /* this is at least correct when domain is our domain, + * which is the only case, when this is currently used: */ + if ((machine_krb5_principal != NULL) && + (asprintf(machine_krb5_principal, "%s$@%s", account_name, + domain->alt_name) == -1)) + { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; +} + /************************************************************************ Given a fd with a just-connected TCP connection to a DC, open a connection to the pipe. @@ -649,7 +683,6 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, char *machine_password = NULL; char *machine_krb5_principal = NULL; char *machine_account = NULL; - const char *account_name = NULL; char *ipc_username = NULL; char *ipc_domain = NULL; char *ipc_password = NULL; @@ -729,22 +762,10 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, { ADS_STATUS ads_status; - if (!get_trust_pw_clear(domain->name, &machine_password, - &account_name, NULL)) - { - result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - goto done; - } - - if (asprintf(&machine_account, "%s$", account_name) == -1) { - result = NT_STATUS_NO_MEMORY; - goto done; - } - - if (asprintf(&machine_krb5_principal, "%s$@%s", account_name, - lp_realm()) == -1) - { - result = NT_STATUS_NO_MEMORY; + result = get_trust_creds(domain, &machine_password, + &machine_account, + &machine_krb5_principal); + if (!NT_STATUS_IS_OK(result)) { goto done; } From e180bbd45452435e981192028a0ad90078c04236 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 11 Dec 2007 16:34:39 +0100 Subject: [PATCH 13/14] Make cm_connect_sam() try harder to connect autheticated. Even if the session setup was anonymous, try and collect trust creds with get_trust_creds() and use these before falling back to schannel. This is the first attempt to fix interdomain trusts. (get password policy and stuff) Michael --- source/winbindd/winbindd_cm.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/source/winbindd/winbindd_cm.c b/source/winbindd/winbindd_cm.c index cc7a0cc6714..cb366a293c0 100644 --- a/source/winbindd/winbindd_cm.c +++ b/source/winbindd/winbindd_cm.c @@ -1968,6 +1968,9 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, NTSTATUS result = NT_STATUS_UNSUCCESSFUL; fstring conn_pwd; struct dcinfo *p_dcinfo; + char *machine_password = NULL; + char *machine_account = NULL; + char *domain_name = NULL; result = init_dc_connection(domain); if (!NT_STATUS_IS_OK(result)) { @@ -1990,34 +1993,46 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, pwd_get_cleartext(&conn->cli->pwd, conn_pwd); if ((conn->cli->user_name[0] == '\0') || (conn->cli->domain[0] == '\0') || - (conn_pwd[0] == '\0')) { - DEBUG(10, ("cm_connect_sam: No no user available for " - "domain %s, trying schannel\n", conn->cli->domain)); + (conn_pwd[0] == '\0')) + { + result = get_trust_creds(domain, &machine_password, + &machine_account, NULL); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10, ("cm_connect_sam: No no user available for " + "domain %s, trying schannel\n", conn->cli->domain)); + goto schannel; + } + domain_name = domain->name; goto schannel; + } else { + machine_password = conn_pwd; + machine_account = conn->cli->user_name; + domain_name = conn->cli->domain; } + /* We have an authenticated connection. Use a NTLMSSP SPNEGO authenticated SAMR pipe with sign & seal. */ conn->samr_pipe = cli_rpc_pipe_open_spnego_ntlmssp(conn->cli, PI_SAMR, PIPE_AUTH_LEVEL_PRIVACY, - conn->cli->domain, - conn->cli->user_name, - conn_pwd, &result); + domain_name, + machine_account, + machine_password, &result); if (conn->samr_pipe == NULL) { DEBUG(10,("cm_connect_sam: failed to connect to SAMR " "pipe for domain %s using NTLMSSP " "authenticated pipe: user %s\\%s. Error was " - "%s\n", domain->name, conn->cli->domain, - conn->cli->user_name, nt_errstr(result))); + "%s\n", domain->name, domain_name, + machine_account, nt_errstr(result))); goto schannel; } DEBUG(10,("cm_connect_sam: connected to SAMR pipe for " "domain %s using NTLMSSP authenticated " "pipe: user %s\\%s\n", domain->name, - conn->cli->domain, conn->cli->user_name )); + domain_name, machine_account)); result = rpccli_samr_connect(conn->samr_pipe, mem_ctx, SEC_RIGHTS_MAXIMUM_ALLOWED, @@ -2102,6 +2117,8 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, *cli = conn->samr_pipe; *sam_handle = conn->sam_domain_handle; + SAFE_FREE(machine_password); + SAFE_FREE(machine_account); return result; } From 537b12647e25adcb7da3581f18d2e9feca1caf0c Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 28 Nov 2007 02:15:37 +0100 Subject: [PATCH 14/14] Add flags for correctly implementing lsa_lookup_name levels. (Prepare fix for Bug #4801.) Michael --- source/include/smb.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source/include/smb.h b/source/include/smb.h index d58c124e6d0..a725ae13929 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -242,6 +242,7 @@ typedef uint64_t NTTIME; #define SID_MAX_SIZE ((size_t)(8+(MAXSUBAUTHS*4))) +#define LOOKUP_NAME_NONE 0x00000000 #define LOOKUP_NAME_ISOLATED 0x00000001 /* Look up unqualified names */ #define LOOKUP_NAME_REMOTE 0x00000002 /* Ask others */ #define LOOKUP_NAME_GROUP 0x00000004 /* (unused) This is a NASTY hack for @@ -250,7 +251,14 @@ typedef uint64_t NTTIME; #define LOOKUP_NAME_EXPLICIT 0x00000008 /* Only include explicitly mapped names and not the Unix {User,Group} domain */ -#define LOOKUP_NAME_ALL (LOOKUP_NAME_ISOLATED|LOOKUP_NAME_REMOTE) +#define LOOKUP_NAME_BUILTIN 0x00000010 /* builtin names */ +#define LOOKUP_NAME_WKN 0x00000020 /* well known names */ +#define LOOKUP_NAME_DOMAIN 0x00000040 /* only lookup own domain */ +#define LOOKUP_NAME_ALL (LOOKUP_NAME_ISOLATED\ + |LOOKUP_NAME_REMOTE\ + |LOOKUP_NAME_BUILTIN\ + |LOOKUP_NAME_WKN\ + |LOOKUP_NAME_DOMAIN) /** * @brief Security Identifier