diff options
author | James Peach <jpeach@samba.org> | 2007-12-13 20:56:53 -0800 |
---|---|---|
committer | James Peach <jpeach@samba.org> | 2007-12-13 20:56:53 -0800 |
commit | 7b457645fb40d7195d75f8e38883b140abcb1955 (patch) | |
tree | 90c3ca21cd40c98ed4c7c1580b75216f689fad97 /source3 | |
parent | 12ac4c3119b3b7712e670d95d61413d97ecafaef (diff) | |
parent | 138333ed1f571cd6bb76c3be655f70e35cd48a99 (diff) | |
download | samba-7b457645fb40d7195d75f8e38883b140abcb1955.tar.gz samba-7b457645fb40d7195d75f8e38883b140abcb1955.tar.bz2 samba-7b457645fb40d7195d75f8e38883b140abcb1955.zip |
Merge branch 'v3-2-test' of git://git.samba.org/samba into v3-2-test
(This used to be commit 0de2b3eb515f2da21ffd1ce54979bb1f8063024b)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/auth/auth_domain.c | 7 | ||||
-rw-r--r-- | source3/auth/token_util.c | 2 | ||||
-rw-r--r-- | source3/client/mount.cifs.c | 71 | ||||
-rw-r--r-- | source3/configure.in | 4 | ||||
-rw-r--r-- | source3/include/smb.h | 10 | ||||
-rw-r--r-- | source3/libsmb/clidgram.c | 6 | ||||
-rw-r--r-- | source3/nmbd/nmbd_packets.c | 6 | ||||
-rw-r--r-- | source3/pam_smbpass/support.c | 8 | ||||
-rw-r--r-- | source3/passdb/lookup_sid.c | 45 | ||||
-rw-r--r-- | source3/passdb/passdb.c | 85 | ||||
-rw-r--r-- | source3/passdb/secrets.c | 67 | ||||
-rw-r--r-- | source3/rpc_client/cli_pipe.c | 126 | ||||
-rw-r--r-- | source3/rpc_server/srv_lsa_nt.c | 37 | ||||
-rw-r--r-- | source3/winbindd/winbindd_cm.c | 145 |
14 files changed, 384 insertions, 235 deletions
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c index 7cddabbbbd..b2c87174fd 100644 --- a/source3/auth/auth_domain.c +++ b/source3/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_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", 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/source3/auth/token_util.c b/source3/auth/token_util.c index 63672bcf74..330acde6e4 100644 --- a/source3/auth/token_util.c +++ b/source3/auth/token_util.c @@ -85,7 +85,7 @@ NT_USER_TOKEN *get_root_nt_token( void ) return token; if ( !(pw = sys_getpwnam( "root" )) ) { - DEBUG(0,("get_root_nt_token: getpwnam\"root\") failed!\n")); + DEBUG(0,("get_root_nt_token: getpwnam(\"root\") failed!\n")); return NULL; } diff --git a/source3/client/mount.cifs.c b/source3/client/mount.cifs.c index f141e8e4c7..ec245ed200 100644 --- a/source3/client/mount.cifs.c +++ b/source3/client/mount.cifs.c @@ -354,6 +354,8 @@ static int parse_options(char ** optionsp, int * filesys_flags) int out_len = 0; int word_len; int rc = 0; + char user[32]; + char group[32]; if (!optionsp || !*optionsp) return 1; @@ -364,6 +366,13 @@ static int parse_options(char ** optionsp, int * filesys_flags) /* BB fixme check for separator override BB */ + if (getuid()) { + got_uid = 1; + snprintf(user,sizeof(user),"%u",getuid()); + got_gid = 1; + snprintf(group,sizeof(group),"%u",getgid()); + } + /* while ((data = strsep(&options, ",")) != NULL) { */ while(data != NULL) { /* check if ends with trailing comma */ @@ -526,33 +535,33 @@ static int parse_options(char ** optionsp, int * filesys_flags) got_uid = 1; if (!isdigit(*value)) { struct passwd *pw; - static char temp[32]; if (!(pw = getpwnam(value))) { printf("bad user name \"%s\"\n", value); exit(1); } - snprintf(temp, sizeof(temp), "%u", pw->pw_uid); - value = temp; - endpwent(); + snprintf(user, sizeof(user), "%u", pw->pw_uid); + } else { + strlcpy(user,value,sizeof(user)); } } + goto nocopy; } else if (strncmp(data, "gid", 3) == 0) { if (value && *value) { got_gid = 1; if (!isdigit(*value)) { struct group *gr; - static char temp[32]; if (!(gr = getgrnam(value))) { printf("bad group name \"%s\"\n", value); exit(1); } - snprintf(temp, sizeof(temp), "%u", gr->gr_gid); - value = temp; - endpwent(); + snprintf(group, sizeof(group), "%u", gr->gr_gid); + } else { + strlcpy(group,value,sizeof(group)); } } + goto nocopy; /* fmask and dmask synonyms for people used to smbfs syntax */ } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) { if (!value || !*value) { @@ -643,17 +652,55 @@ static int parse_options(char ** optionsp, int * filesys_flags) exit(1); } - if (out_len) - out[out_len++] = ','; + if (out_len) { + strlcat(out, ",", out_len + word_len + 2); + out_len++; + } + if (value) - snprintf(out + out_len, word_len + 2, "%s=%s", data, value); + snprintf(out + out_len, word_len + 1, "%s=%s", data, value); else - snprintf(out + out_len, word_len + 2, "%s", data); + snprintf(out + out_len, word_len + 1, "%s", data); out_len = strlen(out); nocopy: data = next_keyword; } + + /* special-case the uid and gid */ + if (got_uid) { + word_len = strlen(user); + + out = (char *)realloc(out, out_len + word_len + 6); + if (out == NULL) { + perror("malloc"); + exit(1); + } + + if (out_len) { + strlcat(out, ",", out_len + word_len + 6); + out_len++; + } + snprintf(out + out_len, word_len + 5, "uid=%s", user); + out_len = strlen(out); + } + if (got_gid) { + word_len = strlen(group); + + out = (char *)realloc(out, out_len + 1 + word_len + 6); + if (out == NULL) { + perror("malloc"); + exit(1); + } + + if (out_len) { + strlcat(out, ",", out_len + word_len + 6); + out_len++; + } + snprintf(out + out_len, word_len + 5, "gid=%s", group); + out_len = strlen(out); + } + free(*optionsp); *optionsp = out; return 0; diff --git a/source3/configure.in b/source3/configure.in index 84ae6f7e50..7272ae4d9a 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -65,10 +65,10 @@ AC_ARG_WITH(fhs, mandir="\${prefix}/share/man" logfilebase="\${VARDIR}/log/samba" privatedir="\${CONFIGDIR}/private" - libdir="\${prefix}/lib/samba" + test "${libdir}" || libdir="\${prefix}/lib/samba" configdir="\${sysconfdir}/samba" swatdir="\${DATADIR}/samba/swat" - codepagedir="\${prefix}/lib/samba" + codepagedir="\${LIBDIR}" statedir="\${VARDIR}/lib/samba" cachedir="\${VARDIR}/lib/samba" AC_DEFINE(FHS_COMPATIBLE, 1, [Whether to use fully FHS-compatible paths]) diff --git a/source3/include/smb.h b/source3/include/smb.h index d58c124e6d..a725ae1392 100644 --- a/source3/include/smb.h +++ b/source3/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 diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c index 82f874f383..76630bd504 100644 --- a/source3/libsmb/clidgram.c +++ b/source3/libsmb/clidgram.c @@ -75,6 +75,12 @@ bool cli_send_mailslot(struct messaging_context *msg_ctx, /* Setup the smb part. */ ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */ memcpy(tmp,ptr,4); + + if (smb_size + 17*2 + strlen(mailslot) + 1 + len > MAX_DGRAM_SIZE) { + DEBUG(0, ("cli_send_mailslot: Cannot write beyond end of packet\n")); + return False; + } + set_message(ptr,17,strlen(mailslot) + 1 + len,True); memcpy(ptr,tmp,4); diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c index b78ab5ba7e..349d36ce70 100644 --- a/source3/nmbd/nmbd_packets.c +++ b/source3/nmbd/nmbd_packets.c @@ -1918,6 +1918,12 @@ bool send_mailslot(bool unique, const char *mailslot,char *buf, size_t len, /* Setup the smb part. */ ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */ memcpy(tmp,ptr,4); + + if (smb_size + 17*2 + strlen(mailslot) + 1 + len > MAX_DGRAM_SIZE) { + DEBUG(0, ("send_mailslot: Cannot write beyond end of packet\n")); + return false; + } + set_message(ptr,17,strlen(mailslot) + 1 + len,True); memcpy(ptr,tmp,4); diff --git a/source3/pam_smbpass/support.c b/source3/pam_smbpass/support.c index 9d56bd4950..bc9481d9e9 100644 --- a/source3/pam_smbpass/support.c +++ b/source3/pam_smbpass/support.c @@ -61,10 +61,6 @@ void _cleanup(pam_handle_t *, void *, int); char *_pam_delete(register char *); - /* default configuration file location */ - - const char *servicesf = get_dyn_CONFIGFILE(); - /* syslogging function for errors and other information */ void _log_err( int err, const char *format, ... ) @@ -128,7 +124,7 @@ int set_ctrl( int flags, int argc, const char **argv ) { int i = 0; - const char *service_file = get_dyn_CONFIGFILE(); + const char *service_file = NULL; unsigned int ctrl; ctrl = SMB_DEFAULTS; /* the default selection of options */ @@ -139,7 +135,7 @@ int set_ctrl( int flags, int argc, const char **argv ) set( SMB__NONULL, ctrl ); /* initialize service file location */ - service_file=servicesf; + service_file=get_dyn_CONFIGFILE(); if (flags & PAM_SILENT) { set( SMB__QUIET, ctrl ); diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index bb54959e96..54db14fbfe 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/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/source3/passdb/passdb.c b/source3/passdb/passdb.c index 2a4d4c4a0a..c4248bb48e 100644 --- a/source3/passdb/passdb.c +++ b/source3/passdb/passdb.c @@ -1521,46 +1521,99 @@ 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 trust account password + 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(const char *domain, uint8 ret_pwd[16], uint32 *channel) +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 */ + * 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)) + if (is_trusted_domain_situation(domain)) { + if (!pdb_get_trusteddom_pw(domain, ret_pwd, NULL, + &last_set_time)) { DEBUG(0, ("get_trust_pw: could not fetch trust " "account password for trusted domain %s\n", domain)); - return False; + return false; } *channel = SEC_CHAN_DOMAIN; - E_md4hash(pwd, ret_pwd); - SAFE_FREE(pwd); - return True; + 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. */ - if (secrets_fetch_trust_account_password(domain, ret_pwd, - &last_set_time, channel)) - return True; + 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. + appropriate account name is stored in account_name. +*******************************************************************/ + +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; + + if (get_trust_pw_clear(domain, &pwd, account_name, channel)) { + E_md4hash(pwd, ret_pwd); + SAFE_FREE(pwd); + return true; + } else if (is_trusted_domain_situation(domain)) { + return false; + } + + /* as a fallback, try to get the hashed pwd directly from the tdb... */ + + if (secrets_fetch_trust_account_password_legacy(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 " + DEBUG(5, ("get_trust_pw_hash: could not fetch trust account " "password for domain %s\n", domain)); return False; } diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c index a4cb76602a..fde7fc0968 100644 --- a/source3/passdb/secrets.c +++ b/source3/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 * @@ -558,20 +576,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 * @@ -722,15 +726,6 @@ char *secrets_fetch_machine_password(const char *domain, } /************************************************************************ - 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 ************************************************************************/ diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 37558a7ff0..f61ea95d04 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -2424,49 +2424,29 @@ 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]; - fstring machine_account; - - netlogon_pipe = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON, perr); - if (!netlogon_pipe) { - return NULL; - } + const char *machine_account; /* Get the machine account credentials from secrets.tdb. */ - if (!get_trust_pw(domain, machine_pwd, &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", domain)); - cli_rpc_pipe_close(netlogon_pipe); *perr = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - return NULL; + return false; } - /* 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 */ @@ -2477,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) { @@ -2489,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; } @@ -2560,61 +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]; - fstring 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(domain, machine_pwd, &sec_chan_type)) { - 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; - } - - /* 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 */ - 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)); + if (!get_schannel_session_key_common(netlogon_pipe, cli, domain, + pneg_flags, perr)) + { cli_rpc_pipe_close(netlogon_pipe); - *perr = NT_STATUS_INVALID_NETWORK_RESPONSE; return NULL; } diff --git a/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c index 20655082a5..c5f0c7b6ab 100644 --- a/source3/rpc_server/srv_lsa_nt.c +++ b/source3/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) { diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 3f6544965d..cb366a293c 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/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. @@ -646,8 +680,12 @@ 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; + char *ipc_username = NULL; + char *ipc_domain = NULL; + char *ipc_password = NULL; bool got_mutex; @@ -661,23 +699,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; - } - - cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password); - *retry = True; got_mutex = secrets_named_mutex(controller, @@ -734,10 +755,20 @@ 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; + result = get_trust_creds(domain, &machine_password, + &machine_account, + &machine_krb5_principal); + if (!NT_STATUS_IS_OK(result)) { + goto done; + } + if (lp_security() == SEC_ADS) { /* Try a krb5 session */ @@ -752,7 +783,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", @@ -762,7 +793,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; } } @@ -772,12 +803,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))); @@ -786,15 +817,17 @@ 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; + cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password); + if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) && (strlen(ipc_username) > 0)) { @@ -1935,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)) { @@ -1957,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, @@ -2069,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; } @@ -2219,10 +2269,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,27 +2280,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 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() ) + if (!get_trust_pw_hash(domain->name, mach_pwd, &account_name, + &sec_chan_type)) { - 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; + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } result = rpccli_netlogon_setup_creds( |