diff options
-rw-r--r-- | source3/auth/auth_domain.c | 101 | ||||
-rw-r--r-- | source3/auth/auth_server.c | 39 | ||||
-rw-r--r-- | source3/auth/auth_util.c | 181 | ||||
-rw-r--r-- | source3/lib/server_mutex.c | 57 |
4 files changed, 282 insertions, 96 deletions
diff --git a/source3/auth/auth_domain.c b/source3/auth/auth_domain.c index b41848076d..8c6bb8908f 100644 --- a/source3/auth/auth_domain.c +++ b/source3/auth/auth_domain.c @@ -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; - - /* Check DOMAIN\username first to catch winbind users, then - just the username for local users. */ + 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 - 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..... */ diff --git a/source3/auth/auth_server.c b/source3/auth/auth_server.c index 0e650aa6e3..919cc8d3d8 100644 --- a/source3/auth/auth_server.c +++ b/source3/auth/auth_server.c @@ -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; } diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index 785815814d..a66cd6ffc7 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -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) { @@ -566,6 +566,179 @@ BOOL make_server_info_guest(auth_serversupplied_info **server_info) } /*************************************************************************** + 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); } diff --git a/source3/lib/server_mutex.c b/source3/lib/server_mutex.c new file mode 100644 index 0000000000..416d77564d --- /dev/null +++ b/source3/lib/server_mutex.c @@ -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); + } +} + |