This patch does 2 things:
authorAndrew Bartlett <abartlet@samba.org>
Sat, 15 Jun 2002 11:15:31 +0000 (11:15 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 15 Jun 2002 11:15:31 +0000 (11:15 +0000)
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 9b0dabdf4ec3bb45879caae76e03b57ccdad8b4b)

source3/auth/auth_domain.c
source3/auth/auth_server.c
source3/auth/auth_util.c
source3/lib/server_mutex.c [new file with mode: 0644]

index b41848076d85857b5b9f12527213cae049a423f2..8c6bb8908fb52a7253ae1220267ee6c2c520653e 100644 (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;
-
-                /* 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..... */
index 0e650aa6e35e3799805699cdda695ad8f02e0e50..919cc8d3d8f64de9a64df6722d3198be300c5798 100644 (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;
 }
 
index 785815814d55845425c0844f11ffe3619ed8738c..a66cd6ffc73909947090847b1430ebd2bcf006be 100644 (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);
 }
diff --git a/source3/lib/server_mutex.c b/source3/lib/server_mutex.c
new file mode 100644 (file)
index 0000000..416d775
--- /dev/null
@@ -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);
+       }
+}
+