Allow Samba to trust NT4 Domains.
authorAndrew Bartlett <abartlet@samba.org>
Sat, 2 Mar 2002 08:25:44 +0000 (08:25 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 2 Mar 2002 08:25:44 +0000 (08:25 +0000)
This commit builds on the auth subsystem to give Samba support for trusting NT4
domains.  It is off by default, but is enabled by adding 'trustdomain' to the
'auth methods' smb.conf paramater.

Tested against NT4 only - there are still some issues with the join code for
Win2k servers (spnego stuff).

The main work TODO involves enumerating the trusted domains (including the RPC
calls to match), and getting winbind to run on the PDC correctly.

Similarly, work remains on getting NT4 to trust Samba domains.

Andrew Bartlett
(This used to be commit ac8c24a9a888a3f916e8b40238b936e6ad743ef7)

source3/auth/auth.c
source3/auth/auth_domain.c
source3/libsmb/cli_netlogon.c
source3/libsmb/trust_passwd.c
source3/nsswitch/winbindd_cm.c
source3/rpcclient/samsync.c
source3/utils/net_rpc_join.c

index 9b78cec95b66e070f19a16f7a795b176989ce99c..e3af9dada67cd151438681b871ebd9837a079d15 100644 (file)
@@ -31,6 +31,7 @@ const struct auth_init_function builtin_auth_init_functions[] = {
        { "unix", auth_init_unix },
        { "smbserver", auth_init_smbserver },
        { "ntdomain", auth_init_ntdomain },
+       { "trustdomain", auth_init_trustdomain },
        { "winbind", auth_init_winbind },
 #ifdef DEVELOPER
        { "name_to_ntstatus", auth_init_name_to_ntstatus },
index 6c858e056c57d489a05b01f7c6cf91fa16251ae3..b57bd2bfcc2489c2b6ae4a702c012a2d3774b3ca 100644 (file)
@@ -38,7 +38,10 @@ extern userdom_struct current_user_info;
  **/
 
 static NTSTATUS connect_to_domain_password_server(struct cli_state **cli, 
-                                                 char *server, unsigned char *trust_passwd)
+                                                 const char *server, 
+                                                 const char *setup_creds_as,
+                                                 uint16 sec_chan,
+                                                 const unsigned char *trust_passwd)
 {
        struct in_addr dest_ip;
        fstring remote_machine;
@@ -121,7 +124,13 @@ machine %s. Error was : %s.\n", remote_machine, cli_errstr(*cli)));
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       result = new_cli_nt_setup_creds(*cli, trust_passwd);
+       snprintf((*cli)->mach_acct, sizeof((*cli)->mach_acct) - 1, "%s$", setup_creds_as);
+
+       if (!(*cli)->mach_acct) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       result = new_cli_nt_setup_creds(*cli, sec_chan, trust_passwd);
 
         if (!NT_STATUS_IS_OK(result)) {
                DEBUG(0,("connect_to_domain_password_server: unable to setup the PDC credentials to machine \
@@ -142,7 +151,9 @@ machine %s. Error was : %s.\n", remote_machine, cli_errstr(*cli)));
 static NTSTATUS attempt_connect_to_dc(struct cli_state **cli, 
                                      const char *domain, 
                                      struct in_addr *ip, 
-                                     unsigned char *trust_passwd)
+                                     const char *setup_creds_as, 
+                                     uint16 sec_chan,
+                                     const unsigned char *trust_passwd)
 {
        fstring dc_name;
 
@@ -156,7 +167,7 @@ static NTSTATUS attempt_connect_to_dc(struct cli_state **cli,
        if (!lookup_dc_name(global_myname, domain, ip, dc_name))
                return NT_STATUS_UNSUCCESSFUL;
 
-       return connect_to_domain_password_server(cli, dc_name, trust_passwd);
+       return connect_to_domain_password_server(cli, dc_name, setup_creds_as, sec_chan, trust_passwd);
 }
 
 /***********************************************************************
@@ -165,6 +176,8 @@ static NTSTATUS attempt_connect_to_dc(struct cli_state **cli,
 ************************************************************************/
 static NTSTATUS find_connect_pdc(struct cli_state **cli, 
                                 const char *domain,
+                                const char *setup_creds_as,
+                                uint16 sec_chan,
                                 unsigned char *trust_passwd, 
                                 time_t last_change_time)
 {
@@ -197,8 +210,10 @@ static NTSTATUS find_connect_pdc(struct cli_state **cli,
                if(!is_local_net(ip_list[i]))
                        continue;
 
-               if(NT_STATUS_IS_OK(nt_status = attempt_connect_to_dc(cli, domain, 
-                                               &ip_list[i], trust_passwd))) 
+               if(NT_STATUS_IS_OK(nt_status = 
+                                  attempt_connect_to_dc(cli, domain, 
+                                                        &ip_list[i], setup_creds_as, 
+                                                        sec_chan, trust_passwd))) 
                        break;
                
                zero_ip(&ip_list[i]); /* Tried and failed. */
@@ -211,9 +226,11 @@ static NTSTATUS find_connect_pdc(struct cli_state **cli,
                i = (sys_random() % count);
 
                if (!is_zero_ip(ip_list[i])) {
-                       if (!NT_STATUS_IS_OK(nt_status = attempt_connect_to_dc(cli, domain, 
-                                               &ip_list[i], trust_passwd)))
-                       zero_ip(&ip_list[i]); /* Tried and failed. */
+                       if (!NT_STATUS_IS_OK(nt_status = 
+                                            attempt_connect_to_dc(cli, domain, 
+                                                                  &ip_list[i], setup_creds_as, 
+                                                                  sec_chan, trust_passwd)))
+                               zero_ip(&ip_list[i]); /* Tried and failed. */
                }
        }
 
@@ -231,7 +248,7 @@ static NTSTATUS find_connect_pdc(struct cli_state **cli,
                                continue;
 
                        if (NT_STATUS_IS_OK(nt_status = attempt_connect_to_dc(cli, domain, 
-                                                 &ip_list[i], trust_passwd)))
+                                                 &ip_list[i], setup_creds_as, sec_chan, trust_passwd)))
                                break;
                }
        }
@@ -251,7 +268,9 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx,
                                       const char *domain,
                                       uchar chal[8],
                                       auth_serversupplied_info **server_info, 
-                                      char *server, unsigned char *trust_passwd,
+                                      char *server, char *setup_creds_as,
+                                      uint16 sec_chan,
+                                      unsigned char *trust_passwd,
                                       time_t last_change_time)
 {
        fstring remote_machine;
@@ -271,9 +290,9 @@ static NTSTATUS domain_client_validate(TALLOC_CTX *mem_ctx,
        while (!NT_STATUS_IS_OK(nt_status) &&
               next_token(&server,remote_machine,LIST_SEP,sizeof(remote_machine))) {
                if(strequal(remote_machine, "*")) {
-                       nt_status = find_connect_pdc(&cli, domain, trust_passwd, last_change_time);
+                       nt_status = find_connect_pdc(&cli, domain, setup_creds_as, sec_chan, trust_passwd, last_change_time);
                } else {
-                       nt_status = connect_to_domain_password_server(&cli, remote_machine, trust_passwd);
+                       nt_status = connect_to_domain_password_server(&cli, remote_machine, setup_creds_as, sec_chan, trust_passwd);
                }
        }
 
@@ -429,7 +448,7 @@ static NTSTATUS check_ntdomain_security(const struct auth_context *auth_context,
 
        if (!secrets_fetch_trust_account_password(domain, trust_passwd, &last_change_time))
        {
-               DEBUG(0, ("check_domain_security: could not fetch trust account password for domain %s\n", lp_workgroup()));
+               DEBUG(0, ("check_ntdomain_security: could not fetch trust account password for domain %s\n", lp_workgroup()));
                return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
 
@@ -449,8 +468,7 @@ static NTSTATUS check_ntdomain_security(const struct auth_context *auth_context,
        nt_status = domain_client_validate(mem_ctx, user_info, domain,
                                           (uchar *)auth_context->challenge.data, 
                                           server_info, 
-                                          password_server, trust_passwd, last_change_time);
-       
+                                          password_server, global_myname, SEC_CHAN_WKSTA, trust_passwd, last_change_time);
        return nt_status;
 }
 
@@ -464,3 +482,90 @@ BOOL auth_init_ntdomain(struct auth_context *auth_context, auth_methods **auth_m
        (*auth_method)->auth = check_ntdomain_security;
        return True;
 }
+
+
+/****************************************************************************
+ Check for a valid username and password in a trusted domain
+****************************************************************************/
+
+static NTSTATUS check_trustdomain_security(const struct auth_context *auth_context,
+                                          void *my_private_data, 
+                                          TALLOC_CTX *mem_ctx,
+                                          const auth_usersupplied_info *user_info, 
+                                          auth_serversupplied_info **server_info)
+{
+       NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
+       unsigned char trust_md4_password[16];
+       char *trust_password;
+       time_t last_change_time;
+       DOM_SID sid;
+
+       if (!user_info || !server_info || !auth_context) {
+               DEBUG(1,("check_trustdomain_security: Critical variables not present.  Failing.\n"));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       /* 
+        * Check that the requested domain is not our own machine name.
+        * If it is, we should never check the PDC here, we use our own local
+        * password file.
+        */
+
+       if(is_netbios_alias_or_name(user_info->domain.str)) {
+               DEBUG(3,("check_trustdomain_security: Requested domain was for this machine.\n"));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       /* 
+        * Check that the requested domain is not our own domain,
+        * If it is, we should use our own local password file.
+        */
+
+       if(strequal(lp_workgroup(), (user_info->domain.str))) {
+               DEBUG(3,("check_trustdomain_security: Requested domain was for this domain.\n"));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       /*
+        * Get the machine account password for the trusted domain
+        * No need to become_root() as secrets_init() is done at startup.
+        */
+
+       if (!secrets_fetch_trusted_domain_password(user_info->domain.str, &trust_password, &sid, &last_change_time))
+       {
+               DEBUG(0, ("check_trustdomain_security: could not fetch trust account password for domain %s\n", user_info->domain.str));
+               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+       }
+
+#ifdef DEBUG_PASSWORD
+       DEBUG(100, ("Trust password for domain %s is %s\n", user_info->domain.str, trust_password));
+#endif
+       E_md4hash((uchar *)trust_password, trust_md4_password);
+       SAFE_FREE(trust_password);
+
+#if 0
+       /* Test if machine password is expired and need to be changed */
+       if (time(NULL) > last_change_time + lp_machine_password_timeout())
+       {
+               global_machine_password_needs_changing = True;
+       }
+#endif
+
+       nt_status = domain_client_validate(mem_ctx, user_info, user_info->domain.str,
+                                          (uchar *)auth_context->challenge.data, 
+                                          server_info, "*" /* Do a lookup */, 
+                                          lp_workgroup(), SEC_CHAN_DOMAIN, trust_md4_password, last_change_time);
+       
+       return nt_status;
+}
+
+/* module initialisation */
+BOOL auth_init_trustdomain(struct auth_context *auth_context, auth_methods **auth_method) 
+{
+       if (!make_auth_methods(auth_context, auth_method)) {
+               return False;
+       }
+
+       (*auth_method)->auth = check_trustdomain_security;
+       return True;
+}
index d550c3e9fa75021b3b512800d3f8a0ef43344cc6..590f5f525ebac294073b2c78e9481c1334338b06 100644 (file)
@@ -93,14 +93,15 @@ Ensure that the server credential returned matches the session key
 encrypt of the server challenge originally received. JRA.
 ****************************************************************************/
 
-NTSTATUS new_cli_net_auth2(struct cli_state *cli, uint16 sec_chan, 
+NTSTATUS new_cli_net_auth2(struct cli_state *cli, 
+                          uint16 sec_chan, 
                            uint32 neg_flags, DOM_CHAL *srv_chal)
 {
         prs_struct qbuf, rbuf;
         NET_Q_AUTH_2 q;
         NET_R_AUTH_2 r;
         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-        extern pstring global_myname;
+       extern pstring global_myname;
 
         prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
         prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
@@ -163,7 +164,8 @@ password ?).\n", cli->desthost ));
 /* Initialize domain session credentials */
 
 NTSTATUS new_cli_nt_setup_creds(struct cli_state *cli, 
-                                unsigned char mach_pwd[16])
+                               uint16 sec_chan,
+                                const unsigned char mach_pwd[16])
 {
         DOM_CHAL clnt_chal;
         DOM_CHAL srv_chal;
@@ -185,7 +187,7 @@ NTSTATUS new_cli_nt_setup_creds(struct cli_state *cli,
         /**************** Long-term Session key **************/
 
         /* calculate the session key */
-        cred_session_key(&clnt_chal, &srv_chal, (char *)mach_pwd, 
+        cred_session_key(&clnt_chal, &srv_chal, mach_pwd, 
                          cli->sess_key);
         memset((char *)cli->sess_key+8, '\0', 8);
 
@@ -201,8 +203,7 @@ NTSTATUS new_cli_nt_setup_creds(struct cli_state *cli,
          * Receive an auth-2 challenge response and check it.
          */
         
-       result = new_cli_net_auth2(cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
-                                  SEC_CHAN_WKSTA : SEC_CHAN_BDC, 0x000001ff, 
+       result = new_cli_net_auth2(cli, sec_chan, 0x000001ff, 
                                   &srv_chal);
        if (!NT_STATUS_IS_OK(result)) {
                 DEBUG(0,("cli_nt_setup_creds: auth2 challenge failed %s\n",
index 069be7f15e3cf0e484f72265adf24da48b19b05d..1f52ab3611b52b2f84d5739e19169a6c945069e0 100644 (file)
@@ -35,7 +35,8 @@ static NTSTATUS just_change_the_password(struct cli_state *cli, TALLOC_CTX *mem_
                                         unsigned char new_trust_passwd_hash[16])
 {
        NTSTATUS result;
-       result = new_cli_nt_setup_creds(cli, orig_trust_passwd_hash);
+       result = new_cli_nt_setup_creds(cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
+                                  SEC_CHAN_WKSTA : SEC_CHAN_BDC, orig_trust_passwd_hash);
        
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(0,("just_change_the_password: unable to setup creds (%s)!\n",
index dcbd47303f3bae8f3374a33e0a92e8942ef8aa94..6ac682fbaba31de7f971ce24625833507b284cf3 100644 (file)
@@ -766,7 +766,8 @@ NTSTATUS cm_get_netlogon_cli(char *domain, unsigned char *trust_passwd,
                return result;
        }
        
-       result = new_cli_nt_setup_creds(conn->cli, trust_passwd);
+       result = new_cli_nt_setup_creds(conn->cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
+                                       SEC_CHAN_WKSTA : SEC_CHAN_BDC, trust_passwd);
 
        if (!NT_STATUS_IS_OK(result)) {
                DEBUG(0, ("error connecting to domain password server: %s\n",
@@ -779,7 +780,8 @@ NTSTATUS cm_get_netlogon_cli(char *domain, unsigned char *trust_passwd,
                        }
                        
                        /* Try again */
-                       result = new_cli_nt_setup_creds(conn->cli, trust_passwd);
+                       result = new_cli_nt_setup_creds(conn->cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
+                                                       SEC_CHAN_WKSTA : SEC_CHAN_BDC, trust_passwd);
                }
                
                if (!NT_STATUS_IS_OK(result)) {
index 3a0bc2d6f69e8945db7aed5cbe2558e6af7b0554..d09ae775ec071f09a54a969e01172ec33a21506e 100644 (file)
@@ -278,7 +278,7 @@ static NTSTATUS sam_sync(struct cli_state *cli, unsigned char trust_passwd[16],
 
         /* Request a challenge */
 
-        if (!NT_STATUS_IS_OK(new_cli_nt_setup_creds(cli, trust_passwd))) {
+        if (!NT_STATUS_IS_OK(new_cli_nt_setup_creds(cli, SEC_CHAN_BDC, trust_passwd))) {
                 DEBUG(0, ("Error initialising session creds\n"));
                 goto done;
         }
index 2fde6291c2a093f55f5a6771ad0fa0b7222947e7..86a00eb9af1c30347d6f64c457d46d7a295144f5 100644 (file)
@@ -273,7 +273,9 @@ int net_rpc_join(int argc, const char **argv)
                goto done;
        }
        
-       CHECK_RPC_ERR(new_cli_nt_setup_creds(cli, stored_md4_trust_password),
+       CHECK_RPC_ERR(new_cli_nt_setup_creds(cli, 
+                                            (acb_info & ACB_SVRTRUST) ? SEC_CHAN_BDC : SEC_CHAN_WKSTA, 
+                                            stored_md4_trust_password),
                          "error in domain join verification");
        
        retval = 0;             /* Success! */