Fix a segv in winbindd caused by trying to free an fstring.
[samba.git] / source / winbindd / winbindd_cm.c
index d5c8b9955f23bbba3a438acc7c1b2f657eb3fc61..6c5633c2b2c90caee983192e7dc55e3f0e133129 100644 (file)
@@ -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,21 +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;
-       }
-
        *retry = True;
 
        got_mutex = secrets_named_mutex(controller,
@@ -732,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 */
@@ -750,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",
@@ -760,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;
                        }
                }
@@ -770,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)));
@@ -784,12 +817,12 @@ 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;
 
@@ -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,10 +1993,26 @@ 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 = SMB_STRDUP(conn_pwd);                
+               machine_account = SMB_STRDUP(conn->cli->user_name);
+               domain_name = conn->cli->domain;
+       }
+
+       if (!machine_password || !machine_account) {
+               result = NT_STATUS_NO_MEMORY;
+               goto done;
        }
 
        /* We have an authenticated connection. Use a NTLMSSP SPNEGO
@@ -1968,23 +2020,23 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
        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 +2121,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;
 }
 
@@ -2235,27 +2289,11 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
                neg_flags |= NETLOGON_NEG_SCHANNEL;
        }
 
-       if (!get_trust_pw(domain->name, mach_pwd, &sec_chan_type)) {
-               cli_rpc_pipe_close(netlogon_pipe);
-               return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-       }
-
-       /* 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(