1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

This patch does 2 things:

It extends the 'server mutex' to conver security=server, becouse the connection
race condition exists here too, and while people *should* use security=domain,
some sites don't....

(This probably should be done in 2.2 as well).

Also, start to actually extract and use the information that the remote
server returns in the info3 struct.

The server mutex code is now in a new file.

Andrew Bartlett
(This used to be commit 9b0dabdf4e)
This commit is contained in:
Andrew Bartlett 2002-06-15 11:15:31 +00:00
parent 209fcbfb92
commit b075458ee7
4 changed files with 282 additions and 96 deletions

View File

@ -29,32 +29,6 @@ BOOL global_machine_password_needs_changing = False;
extern pstring global_myname;
extern userdom_struct current_user_info;
static char *mutex_server_name;
static BOOL grab_server_mutex(const char *name)
{
mutex_server_name = strdup(name);
if (!mutex_server_name) {
DEBUG(0,("grab_server_mutex: malloc failed for %s\n", name));
return False;
}
if (!message_named_mutex(name, 20)) {
DEBUG(10,("grab_server_mutex: failed for %s\n", name));
SAFE_FREE(mutex_server_name);
return False;
}
return True;
}
static void release_server_mutex(void)
{
if (mutex_server_name) {
message_named_mutex_release(mutex_server_name);
SAFE_FREE(mutex_server_name);
}
}
/**
* Connect to a remote server for domain security authenticaion.
*
@ -113,9 +87,10 @@ static NTSTATUS connect_to_domain_password_server(struct cli_state **cli,
logonserver. We can avoid a 30-second timeout if the DC is down
if the SAMLOGON request fails as it is only over UDP. */
/* we use a mutex to prevent two connections at once - when a NT PDC gets
two connections where one hasn't completed a negprot yet it will send a
TCP reset to the first connection (tridge) */
/* we use a mutex to prevent two connections at once - when a
Win2k PDC get two connections where one hasn't completed a
session setup yet it will send a TCP reset to the first
connection (tridge) */
/*
* With NT4.x DC's *all* authentication must be serialized to avoid
@ -307,14 +282,13 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx,
auth_serversupplied_info **server_info,
char *server, char *setup_creds_as,
uint16 sec_chan,
unsigned char *trust_passwd,
unsigned char trust_passwd[16],
time_t last_change_time)
{
fstring remote_machine;
NET_USER_INFO_3 info3;
struct cli_state *cli = NULL;
NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
struct passwd *pass;
/*
* At this point, smb_apasswd points to the lanman response to
@ -358,63 +332,14 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx,
user_info->domain.str, cli->srv_name_slash,
nt_errstr(nt_status)));
} else {
char *dom_user;
nt_status = make_server_info_info3(mem_ctx, domain, server_info, &info3);
#if 0
/* The stuff doesn't work right yet */
SMB_ASSERT(sizeof((*server_info)->session_key) == sizeof(info3.user_sess_key));
memcpy((*server_info)->session_key, info3.user_sess_key, sizeof((*server_info)->session_key)/* 16 */);
SamOEMhash((*server_info)->session_key, trust_passwd, sizeof((*server_info)->session_key));
#endif
/* Check DOMAIN\username first to catch winbind users, then
just the username for local users. */
dom_user = talloc_asprintf(mem_ctx, "%s%s%s", user_info->domain.str,
lp_winbind_separator(),
user_info->internal_username.str);
if (!dom_user) {
DEBUG(0, ("talloc_asprintf failed!\n"));
nt_status = NT_STATUS_NO_MEMORY;
} else {
if (!(pass = Get_Pwnam(dom_user)))
pass = Get_Pwnam(user_info->internal_username.str);
if (pass) {
make_server_info_pw(server_info, pass);
if (!server_info) {
nt_status = NT_STATUS_NO_MEMORY;
}
} else {
nt_status = NT_STATUS_NO_SUCH_USER;
}
}
}
/* Store the user group information in the server_info returned to the caller. */
if (NT_STATUS_IS_OK(nt_status) && (info3.num_groups2 != 0)) {
int i;
NT_USER_TOKEN *ptok;
auth_serversupplied_info *pserver_info = *server_info;
if ((pserver_info->ptok = malloc( sizeof(NT_USER_TOKEN) ) ) == NULL) {
DEBUG(0, ("domain_client_validate: out of memory allocating rid group membership\n"));
nt_status = NT_STATUS_NO_MEMORY;
free_server_info(server_info);
goto done;
}
ptok = pserver_info->ptok;
ptok->num_sids = (size_t)info3.num_groups2;
if ((ptok->user_sids = (DOM_SID *)malloc( sizeof(DOM_SID) * ptok->num_sids )) == NULL) {
DEBUG(0, ("domain_client_validate: Out of memory allocating group SIDS\n"));
nt_status = NT_STATUS_NO_MEMORY;
free_server_info(server_info);
goto done;
}
for (i = 0; i < ptok->num_sids; i++) {
sid_copy(&ptok->user_sids[i], &info3.dom_sid.sid);
sid_append_rid(&ptok->user_sids[i], info3.gids[i].g_rid);
}
uni_group_cache_store_netlogon(mem_ctx, &info3);
}
@ -434,8 +359,6 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx,
}
#endif /* 0 */
done:
/* Note - once the cli stream is shutdown the mem_ctx used
to allocate the other_sids and gids structures has been deleted - so
these pointers are no longer valid..... */

View File

@ -62,6 +62,15 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx)
continue;
}
/* we use a mutex to prevent two connections at once - when a
Win2k PDC get two connections where one hasn't completed a
session setup yet it will send a TCP reset to the first
connection (tridge) */
if (!grab_server_mutex(desthost)) {
return NULL;
}
if (cli_connect(cli, desthost, &dest_ip)) {
DEBUG(3,("connected to password server %s\n",desthost));
connected_ok = True;
@ -70,13 +79,19 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx)
}
if (!connected_ok) {
release_server_mutex();
DEBUG(0,("password server not available\n"));
cli_shutdown(cli);
return NULL;
}
if (!attempt_netbios_session_request(cli, global_myname, desthost, &dest_ip))
if (!attempt_netbios_session_request(cli, global_myname,
desthost, &dest_ip)) {
release_server_mutex();
DEBUG(1,("password server fails session request\n"));
cli_shutdown(cli);
return NULL;
}
if (strequal(desthost,myhostname())) {
exit_server("Password server loop!");
@ -86,6 +101,7 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx)
if (!cli_negprot(cli)) {
DEBUG(1,("%s rejected the negprot\n",desthost));
release_server_mutex();
cli_shutdown(cli);
return NULL;
}
@ -93,12 +109,29 @@ static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx)
if (cli->protocol < PROTOCOL_LANMAN2 ||
!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
DEBUG(1,("%s isn't in user level security mode\n",desthost));
release_server_mutex();
cli_shutdown(cli);
return NULL;
}
DEBUG(3,("password server OK\n"));
/* Get the first session setup done quickly, to avoid silly
Win2k bugs. (The next connection to the server will kill
this one...
*/
if (!cli_session_setup(cli, "", "", 0, "", 0,
"")) {
DEBUG(0,("%s rejected the initial session setup (%s)\n",
desthost, cli_errstr(cli)));
release_server_mutex();
cli_shutdown(cli);
return NULL;
}
release_server_mutex();
DEBUG(3,("password server OK\n"));
return cli;
}

View File

@ -460,7 +460,7 @@ BOOL make_user_info_guest(auth_usersupplied_info **user_info)
Make a user_info struct
***************************************************************************/
BOOL make_server_info(auth_serversupplied_info **server_info)
static BOOL make_server_info(auth_serversupplied_info **server_info)
{
*server_info = malloc(sizeof(**server_info));
if (!*server_info) {
@ -565,6 +565,179 @@ BOOL make_server_info_guest(auth_serversupplied_info **server_info)
return False;
}
/***************************************************************************
Make a server_info struct from the info3 returned by a domain logon
***************************************************************************/
NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
const char *domain,
auth_serversupplied_info **server_info,
NET_USER_INFO_3 *info3)
{
NTSTATUS nt_status = NT_STATUS_OK;
char *nt_domain;
char *nt_username;
SAM_ACCOUNT *sam_account = NULL;
DOM_SID user_sid;
DOM_SID group_sid;
struct passwd *passwd;
uid_t uid;
gid_t gid;
/*
Here is where we should check the list of
trusted domains, and verify that the SID
matches.
*/
sid_copy(&user_sid, &info3->dom_sid.sid);
if (!sid_append_rid(&user_sid, info3->user_rid)) {
return NT_STATUS_INVALID_PARAMETER;
}
sid_copy(&group_sid, &info3->dom_sid.sid);
if (!sid_append_rid(&group_sid, info3->group_rid)) {
return NT_STATUS_INVALID_PARAMETER;
}
if (!(nt_username = unistr2_tdup(mem_ctx, &(info3->uni_user_name)))) {
return NT_STATUS_NO_MEMORY;
}
if (!(nt_domain = unistr2_tdup(mem_ctx, &(info3->uni_logon_dom)))) {
return NT_STATUS_NO_MEMORY;
}
if (winbind_sid_to_uid(&uid, &user_sid)
&& winbind_sid_to_gid(&gid, &group_sid)
&& ((passwd = getpwuid_alloc(uid)))) {
nt_status = pdb_init_sam_pw(&sam_account, passwd);
passwd_free(&passwd);
} else {
char *dom_user;
dom_user = talloc_asprintf(mem_ctx, "%s%s%s",
nt_domain,
lp_winbind_separator(),
nt_username);
if (!dom_user) {
DEBUG(0, ("talloc_asprintf failed!\n"));
return NT_STATUS_NO_MEMORY;
} else {
if (!(passwd = Get_Pwnam(dom_user))
/* Only lookup local for the local
domain, we don't want this for
trusted domains */
&& strequal(nt_domain, lp_workgroup())) {
passwd = Get_Pwnam(nt_username);
}
if (passwd) {
return NT_STATUS_NO_SUCH_USER;
} else {
nt_status = pdb_init_sam_pw(&sam_account, passwd);
}
}
}
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0, ("make_server_info_info3: pdb_init_sam failed!\n"));
return nt_status;
}
if (!pdb_set_user_sid(sam_account, &user_sid)) {
pdb_free_sam(&sam_account);
return NT_STATUS_UNSUCCESSFUL;
}
if (!pdb_set_group_sid(sam_account, &group_sid)) {
pdb_free_sam(&sam_account);
return NT_STATUS_UNSUCCESSFUL;
}
if (!pdb_set_nt_username(sam_account, nt_username)) {
pdb_free_sam(&sam_account);
return NT_STATUS_NO_MEMORY;
}
if (!pdb_set_domain(sam_account, nt_domain)) {
pdb_free_sam(&sam_account);
return NT_STATUS_NO_MEMORY;
}
if (!pdb_set_fullname(sam_account, pdb_unistr2_convert(&(info3->uni_full_name)))) {
pdb_free_sam(&sam_account);
return NT_STATUS_NO_MEMORY;
}
if (!pdb_set_logon_script(sam_account, pdb_unistr2_convert(&(info3->uni_logon_script)), True)) {
pdb_free_sam(&sam_account);
return NT_STATUS_NO_MEMORY;
}
if (!pdb_set_profile_path(sam_account, pdb_unistr2_convert(&(info3->uni_profile_path)), True)) {
pdb_free_sam(&sam_account);
return NT_STATUS_NO_MEMORY;
}
if (!pdb_set_homedir(sam_account, pdb_unistr2_convert(&(info3->uni_home_dir)), True)) {
pdb_free_sam(&sam_account);
return NT_STATUS_NO_MEMORY;
}
if (!pdb_set_dir_drive(sam_account, pdb_unistr2_convert(&(info3->uni_dir_drive)), True)) {
pdb_free_sam(&sam_account);
return NT_STATUS_NO_MEMORY;
}
if (!make_server_info_sam(server_info, sam_account)) {
DEBUG(0, ("make_server_info_info3: make_server_info_sam failed!\n"));
pdb_free_sam(&sam_account);
return NT_STATUS_NO_MEMORY;
}
/* Store the user group information in the server_info
returned to the caller. */
if (info3->num_groups2 != 0) {
int i;
NT_USER_TOKEN *ptok;
auth_serversupplied_info *pserver_info = *server_info;
if ((pserver_info->ptok = malloc( sizeof(NT_USER_TOKEN) ) ) == NULL) {
DEBUG(0, ("domain_client_validate: out of memory allocating rid group membership\n"));
nt_status = NT_STATUS_NO_MEMORY;
free_server_info(server_info);
return nt_status;
}
ptok = pserver_info->ptok;
ptok->num_sids = (size_t)info3->num_groups2;
if ((ptok->user_sids = (DOM_SID *)malloc( sizeof(DOM_SID) * ptok->num_sids )) == NULL) {
DEBUG(0, ("domain_client_validate: Out of memory allocating group SIDS\n"));
nt_status = NT_STATUS_NO_MEMORY;
free_server_info(server_info);
return nt_status;
}
for (i = 0; i < ptok->num_sids; i++) {
sid_copy(&ptok->user_sids[i], &(info3->dom_sid.sid));
if (!sid_append_rid(&ptok->user_sids[i], info3->gids[i].g_rid)) {
nt_status = NT_STATUS_INVALID_PARAMETER;
free_server_info(server_info);
return nt_status;
}
}
}
return NT_STATUS_OK;
}
/***************************************************************************
Make an auth_methods struct
***************************************************************************/
@ -596,9 +769,9 @@ BOOL make_auth_methods(struct auth_context *auth_context, auth_methods **auth_me
void delete_nt_token(NT_USER_TOKEN **pptoken)
{
if (*pptoken) {
NT_USER_TOKEN *ptoken = *pptoken;
SAFE_FREE( ptoken->user_sids );
ZERO_STRUCTP(ptoken);
NT_USER_TOKEN *ptoken = *pptoken;
SAFE_FREE( ptoken->user_sids );
ZERO_STRUCTP(ptoken);
}
SAFE_FREE(*pptoken);
}

View File

@ -0,0 +1,57 @@
/*
Unix SMB/CIFS implementation.
Authenticate against a remote domain
Copyright (C) Andrew Tridgell 1992-2002
Copyright (C) Andrew Bartlett 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
/* For reasons known only to MS, many of their NT/Win2k versions
need serialised access only. Two connections at the same time
may (in certain situations) cause connections to be reset,
or access to be denied.
This locking allows smbd's mutlithread architecture to look
like the single-connection that NT makes. */
static char *mutex_server_name;
BOOL grab_server_mutex(const char *name)
{
mutex_server_name = strdup(name);
if (!mutex_server_name) {
DEBUG(0,("grab_server_mutex: malloc failed for %s\n", name));
return False;
}
if (!message_named_mutex(mutex_server_name, 20)) {
DEBUG(10,("grab_server_mutex: failed for %s\n", name));
SAFE_FREE(mutex_server_name);
return False;
}
return True;
}
void release_server_mutex(void)
{
if (mutex_server_name) {
message_named_mutex_release(mutex_server_name);
SAFE_FREE(mutex_server_name);
}
}