CVE-2015-0240: s3: netlogon: Ensure we don't call talloc_free on an uninitialized...
[metze/samba/wip.git] / source3 / rpc_server / netlogon / srv_netlog_nt.c
index fdbe9373a8767f9ef5e30ba5f2e517ded36b846a..34b9a024d65b2a09ee4a6b1c60ac90ee0676816b 100644 (file)
@@ -506,7 +506,8 @@ static NTSTATUS samr_find_machine_account(TALLOC_CTX *mem_ctx,
 {
        NTSTATUS status;
        NTSTATUS result = NT_STATUS_OK;
-       struct policy_handle connect_handle, domain_handle;
+       struct policy_handle connect_handle;
+       struct policy_handle domain_handle = { 0, };
        struct lsa_String domain_name;
        struct dom_sid2 *domain_sid;
        struct lsa_String names;
@@ -579,7 +580,7 @@ static NTSTATUS samr_find_machine_account(TALLOC_CTX *mem_ctx,
                status = NT_STATUS_NO_SUCH_USER;
                goto out;
        }
-       if (rids.count != types.count) {
+       if (types.count != 1) {
                status = NT_STATUS_INVALID_PARAMETER;
                goto out;
        }
@@ -908,6 +909,10 @@ NTSTATUS _netr_ServerAuthenticate3(struct pipes_struct *p,
                srv_flgs |= NETLOGON_NEG_STRONG_KEYS;
        }
 
+       if (in_neg_flags & NETLOGON_NEG_SUPPORTS_AES) {
+               srv_flgs |= NETLOGON_NEG_SUPPORTS_AES;
+       }
+
        if (lp_server_schannel() != false) {
                srv_flgs |= NETLOGON_NEG_SCHANNEL;
        }
@@ -1000,7 +1005,7 @@ NTSTATUS _netr_ServerAuthenticate3(struct pipes_struct *p,
                goto out;
        }
 
-       lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_context());
+       lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers());
        if (lp_ctx == NULL) {
                DEBUG(10, ("loadparm_init_s3 failed\n"));
                status = NT_STATUS_INTERNAL_ERROR;
@@ -1096,6 +1101,10 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
        bool schannel_global_required = (lp_server_schannel() == true) ? true:false;
        struct loadparm_context *lp_ctx;
 
+       if (creds_out != NULL) {
+               *creds_out = NULL;
+       }
+
        if (schannel_global_required) {
                status = schannel_check_required(&p->auth,
                                                 computer_name,
@@ -1105,7 +1114,7 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p,
                }
        }
 
-       lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_context());
+       lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
        if (lp_ctx == NULL) {
                DEBUG(0, ("loadparm_init_s3 failed\n"));
                return NT_STATUS_INTERNAL_ERROR;
@@ -1137,9 +1146,17 @@ static NTSTATUS netr_set_machine_account_password(TALLOC_CTX *mem_ctx,
        struct samr_UserInfo18 info18;
        DATA_BLOB in,out;
        int rc;
+       DATA_BLOB session_key;
 
        ZERO_STRUCT(user_handle);
 
+       status = session_extract_session_key(session_info,
+                                            &session_key,
+                                            KEY_USE_16BYTES);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
+
        rc = tsocket_address_inet_from_strings(mem_ctx,
                                               "ip",
                                               "127.0.0.1",
@@ -1205,7 +1222,7 @@ static NTSTATUS netr_set_machine_account_password(TALLOC_CTX *mem_ctx,
 
        in = data_blob_const(nt_hash->hash, 16);
        out = data_blob_talloc_zero(mem_ctx, 16);
-       sess_crypt_blob(&out, &in, &session_info->session_key, true);
+       sess_crypt_blob(&out, &in, &session_key, true);
        memcpy(info18.nt_pwd.hash, out.data, out.length);
 
        info18.nt_pwd_active = true;
@@ -1245,7 +1262,7 @@ NTSTATUS _netr_ServerPasswordSet(struct pipes_struct *p,
 {
        NTSTATUS status = NT_STATUS_OK;
        int i;
-       struct netlogon_creds_CredentialState *creds;
+       struct netlogon_creds_CredentialState *creds = NULL;
 
        DEBUG(5,("_netr_ServerPasswordSet: %d\n", __LINE__));
 
@@ -1319,7 +1336,12 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p,
 
        memcpy(password_buf.data, r->in.new_password->data, 512);
        SIVAL(password_buf.data, 512, r->in.new_password->length);
-       netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
+
+       if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+               netlogon_creds_aes_decrypt(creds, password_buf.data, 516);
+       } else {
+               netlogon_creds_arcfour_crypt(creds, password_buf.data, 516);
+       }
 
        if (!extract_pw_from_buffer(p->mem_ctx, password_buf.data, &plaintext)) {
                TALLOC_FREE(creds);
@@ -1447,21 +1469,17 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
        struct auth_usersupplied_info *user_info = NULL;
        struct auth_serversupplied_info *server_info = NULL;
        struct auth_context *auth_context = NULL;
-       uint8_t pipe_session_key[16];
-       bool process_creds = true;
        const char *fn;
+       struct netr_SamBaseInfo *base;
 
        switch (p->opnum) {
                case NDR_NETR_LOGONSAMLOGON:
-                       process_creds = true;
                        fn = "_netr_LogonSamLogon";
                        break;
                case NDR_NETR_LOGONSAMLOGONWITHFLAGS:
-                       process_creds = true;
                        fn = "_netr_LogonSamLogonWithFlags";
                        break;
                case NDR_NETR_LOGONSAMLOGONEX:
-                       process_creds = false;
                        fn = "_netr_LogonSamLogonEx";
                        break;
                default:
@@ -1578,13 +1596,46 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
        {
                uint8_t chal[8];
 
+#ifdef DEBUG_PASSWORD
+               DEBUG(100,("lm owf password:"));
+               dump_data(100, logon->password->lmpassword.hash, 16);
+
+               DEBUG(100,("nt owf password:"));
+               dump_data(100, logon->password->ntpassword.hash, 16);
+#endif
+               if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+                       netlogon_creds_aes_decrypt(creds,
+                                                  logon->password->lmpassword.hash,
+                                                  16);
+                       netlogon_creds_aes_decrypt(creds,
+                                                  logon->password->ntpassword.hash,
+                                                  16);
+               } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+                       netlogon_creds_arcfour_crypt(creds,
+                                                    logon->password->lmpassword.hash,
+                                                    16);
+                       netlogon_creds_arcfour_crypt(creds,
+                                                    logon->password->ntpassword.hash,
+                                                    16);
+               } else {
+                       netlogon_creds_des_decrypt(creds, &logon->password->lmpassword);
+                       netlogon_creds_des_decrypt(creds, &logon->password->ntpassword);
+               }
+
+#ifdef DEBUG_PASSWORD
+               DEBUG(100,("decrypt of lm owf password:"));
+               dump_data(100, logon->password->lmpassword.hash, 16);
+
+               DEBUG(100,("decrypt of nt owf password:"));
+               dump_data(100, logon->password->ntpassword.hash, 16);
+#endif
                status = make_auth_context_subsystem(talloc_tos(),
                                                     &auth_context);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
 
-               auth_context->get_ntlm_challenge(auth_context, chal);
+               auth_get_ntlm_challenge(auth_context, chal);
 
                if (!make_user_info_netlogon_interactive(&user_info,
                                                         nt_username, nt_domain,
@@ -1593,8 +1644,7 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
                                                         logon->password->identity_info.parameter_control,
                                                         chal,
                                                         logon->password->lmpassword.hash,
-                                                        logon->password->ntpassword.hash,
-                                                        creds->session_key)) {
+                                                        logon->password->ntpassword.hash)) {
                        status = NT_STATUS_NO_MEMORY;
                }
                break;
@@ -1605,7 +1655,7 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
        } /* end switch */
 
        if ( NT_STATUS_IS_OK(status) ) {
-               status = auth_context->check_ntlm_password(auth_context,
+               status = auth_check_ntlm_password(auth_context,
                        user_info, &server_info);
        }
 
@@ -1643,40 +1693,47 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
            the SAM Local Security Authority should record that the user is
            logged in to the domain.  */
 
-       if (process_creds) {
-               /* Get the pipe session key from the creds. */
-               memcpy(pipe_session_key, creds->session_key, 16);
-       } else {
-               struct schannel_state *schannel_auth;
-               /* Get the pipe session key from the schannel. */
-               if ((p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL)
-                   || (p->auth.auth_ctx == NULL)) {
-                       return NT_STATUS_INVALID_HANDLE;
-               }
-
-               schannel_auth = talloc_get_type_abort(p->auth.auth_ctx,
-                                                     struct schannel_state);
-               memcpy(pipe_session_key, schannel_auth->creds->session_key, 16);
-       }
-
        switch (r->in.validation_level) {
        case 2:
-               status = serverinfo_to_SamInfo2(server_info, pipe_session_key, 16,
+               status = serverinfo_to_SamInfo2(server_info,
                                                r->out.validation->sam2);
+               base = &r->out.validation->sam2->base;
                break;
        case 3:
-               status = serverinfo_to_SamInfo3(server_info, pipe_session_key, 16,
+               status = serverinfo_to_SamInfo3(server_info,
                                                r->out.validation->sam3);
+               base = &r->out.validation->sam3->base;
                break;
        case 6:
-               status = serverinfo_to_SamInfo6(server_info, pipe_session_key, 16,
+               status = serverinfo_to_SamInfo6(server_info,
                                                r->out.validation->sam6);
+               base = &r->out.validation->sam6->base;
                break;
        }
 
        TALLOC_FREE(server_info);
 
-       return status;
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (r->in.validation_level == 6) {
+               /* no further crypto to be applied - gd */
+               return NT_STATUS_OK;
+       }
+
+       if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+               netlogon_creds_aes_encrypt(creds, base->key.key, 16);
+               netlogon_creds_aes_encrypt(creds, base->LMSessKey.key, 8);
+       } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+               netlogon_creds_arcfour_crypt(creds, base->key.key, 16);
+               netlogon_creds_arcfour_crypt(creds, base->LMSessKey.key, 8);
+       } else {
+               /* key is unencrypted when neither AES nor RC4 bits are set */
+               netlogon_creds_des_encrypt_LMKey(creds, &base->LMSessKey);
+       }
+
+       return NT_STATUS_OK;
 }
 
 /****************************************************************
@@ -1781,7 +1838,7 @@ NTSTATUS _netr_LogonSamLogonEx(struct pipes_struct *p,
                return NT_STATUS_INVALID_PARAMETER;
         }
 
-       lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_context());
+       lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers());
        if (lp_ctx == NULL) {
                DEBUG(0, ("loadparm_init_s3 failed\n"));
                return NT_STATUS_INTERNAL_ERROR;
@@ -1829,7 +1886,7 @@ NTSTATUS _netr_LogonSamLogonEx(struct pipes_struct *p,
 WERROR _netr_LogonUasLogon(struct pipes_struct *p,
                           struct netr_LogonUasLogon *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -1839,7 +1896,7 @@ WERROR _netr_LogonUasLogon(struct pipes_struct *p,
 WERROR _netr_LogonUasLogoff(struct pipes_struct *p,
                            struct netr_LogonUasLogoff *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -1849,7 +1906,7 @@ WERROR _netr_LogonUasLogoff(struct pipes_struct *p,
 NTSTATUS _netr_DatabaseDeltas(struct pipes_struct *p,
                              struct netr_DatabaseDeltas *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
@@ -1859,7 +1916,7 @@ NTSTATUS _netr_DatabaseDeltas(struct pipes_struct *p,
 NTSTATUS _netr_DatabaseSync(struct pipes_struct *p,
                            struct netr_DatabaseSync *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
@@ -1869,7 +1926,7 @@ NTSTATUS _netr_DatabaseSync(struct pipes_struct *p,
 NTSTATUS _netr_AccountDeltas(struct pipes_struct *p,
                             struct netr_AccountDeltas *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
@@ -1879,7 +1936,7 @@ NTSTATUS _netr_AccountDeltas(struct pipes_struct *p,
 NTSTATUS _netr_AccountSync(struct pipes_struct *p,
                           struct netr_AccountSync *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
@@ -2020,7 +2077,7 @@ WERROR _netr_GetAnyDCName(struct pipes_struct *p,
 NTSTATUS _netr_DatabaseSync2(struct pipes_struct *p,
                             struct netr_DatabaseSync2 *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
@@ -2030,7 +2087,7 @@ NTSTATUS _netr_DatabaseSync2(struct pipes_struct *p,
 NTSTATUS _netr_DatabaseRedo(struct pipes_struct *p,
                            struct netr_DatabaseRedo *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
@@ -2040,7 +2097,7 @@ NTSTATUS _netr_DatabaseRedo(struct pipes_struct *p,
 WERROR _netr_DsRGetDCName(struct pipes_struct *p,
                          struct netr_DsRGetDCName *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2079,7 +2136,7 @@ NTSTATUS _netr_LogonGetCapabilities(struct pipes_struct *p,
 WERROR _netr_NETRLOGONSETSERVICEBITS(struct pipes_struct *p,
                                     struct netr_NETRLOGONSETSERVICEBITS *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2089,7 +2146,7 @@ WERROR _netr_NETRLOGONSETSERVICEBITS(struct pipes_struct *p,
 WERROR _netr_LogonGetTrustRid(struct pipes_struct *p,
                              struct netr_LogonGetTrustRid *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2099,7 +2156,7 @@ WERROR _netr_LogonGetTrustRid(struct pipes_struct *p,
 WERROR _netr_NETRLOGONCOMPUTESERVERDIGEST(struct pipes_struct *p,
                                          struct netr_NETRLOGONCOMPUTESERVERDIGEST *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2109,7 +2166,7 @@ WERROR _netr_NETRLOGONCOMPUTESERVERDIGEST(struct pipes_struct *p,
 WERROR _netr_NETRLOGONCOMPUTECLIENTDIGEST(struct pipes_struct *p,
                                          struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2119,7 +2176,7 @@ WERROR _netr_NETRLOGONCOMPUTECLIENTDIGEST(struct pipes_struct *p,
 WERROR _netr_DsRGetDCNameEx(struct pipes_struct *p,
                            struct netr_DsRGetDCNameEx *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2129,7 +2186,7 @@ WERROR _netr_DsRGetDCNameEx(struct pipes_struct *p,
 WERROR _netr_DsRGetSiteName(struct pipes_struct *p,
                            struct netr_DsRGetSiteName *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2139,7 +2196,7 @@ WERROR _netr_DsRGetSiteName(struct pipes_struct *p,
 NTSTATUS _netr_LogonGetDomainInfo(struct pipes_struct *p,
                                  struct netr_LogonGetDomainInfo *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
@@ -2149,7 +2206,7 @@ NTSTATUS _netr_LogonGetDomainInfo(struct pipes_struct *p,
 WERROR _netr_ServerPasswordGet(struct pipes_struct *p,
                               struct netr_ServerPasswordGet *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2159,7 +2216,7 @@ WERROR _netr_ServerPasswordGet(struct pipes_struct *p,
 WERROR _netr_NETRLOGONSENDTOSAM(struct pipes_struct *p,
                                struct netr_NETRLOGONSENDTOSAM *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2169,7 +2226,7 @@ WERROR _netr_NETRLOGONSENDTOSAM(struct pipes_struct *p,
 WERROR _netr_DsRAddressToSitenamesW(struct pipes_struct *p,
                                    struct netr_DsRAddressToSitenamesW *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2179,7 +2236,7 @@ WERROR _netr_DsRAddressToSitenamesW(struct pipes_struct *p,
 WERROR _netr_DsRGetDCNameEx2(struct pipes_struct *p,
                             struct netr_DsRGetDCNameEx2 *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2189,7 +2246,7 @@ WERROR _netr_DsRGetDCNameEx2(struct pipes_struct *p,
 WERROR _netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct pipes_struct *p,
                                                 struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2199,7 +2256,7 @@ WERROR _netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct pipes_struct *p,
 WERROR _netr_NetrEnumerateTrustedDomainsEx(struct pipes_struct *p,
                                           struct netr_NetrEnumerateTrustedDomainsEx *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2209,7 +2266,7 @@ WERROR _netr_NetrEnumerateTrustedDomainsEx(struct pipes_struct *p,
 WERROR _netr_DsRAddressToSitenamesExW(struct pipes_struct *p,
                                      struct netr_DsRAddressToSitenamesExW *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2219,7 +2276,7 @@ WERROR _netr_DsRAddressToSitenamesExW(struct pipes_struct *p,
 WERROR _netr_DsrGetDcSiteCoverageW(struct pipes_struct *p,
                                   struct netr_DsrGetDcSiteCoverageW *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2229,7 +2286,7 @@ WERROR _netr_DsrGetDcSiteCoverageW(struct pipes_struct *p,
 WERROR _netr_DsrEnumerateDomainTrusts(struct pipes_struct *p,
                                      struct netr_DsrEnumerateDomainTrusts *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2239,7 +2296,7 @@ WERROR _netr_DsrEnumerateDomainTrusts(struct pipes_struct *p,
 WERROR _netr_DsrDeregisterDNSHostRecords(struct pipes_struct *p,
                                         struct netr_DsrDeregisterDNSHostRecords *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return WERR_NOT_SUPPORTED;
 }
 
@@ -2249,29 +2306,23 @@ WERROR _netr_DsrDeregisterDNSHostRecords(struct pipes_struct *p,
 NTSTATUS _netr_ServerTrustPasswordsGet(struct pipes_struct *p,
                                       struct netr_ServerTrustPasswordsGet *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
 /****************************************************************
 ****************************************************************/
 
-WERROR _netr_DsRGetForestTrustInformation(struct pipes_struct *p,
-                                         struct netr_DsRGetForestTrustInformation *r)
-{
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
-****************************************************************/
-
 static NTSTATUS fill_forest_trust_array(TALLOC_CTX *mem_ctx,
                                        struct lsa_ForestTrustInformation *info)
 {
        struct lsa_ForestTrustRecord *e;
        struct pdb_domain_info *dom_info;
        struct lsa_ForestTrustDomainInfo *domain_info;
+       char **upn_suffixes = NULL;
+       uint32_t num_suffixes = 0;
+       uint32_t i = 0;
+       NTSTATUS status;
 
        dom_info = pdb_get_domain_info(mem_ctx);
        if (dom_info == NULL) {
@@ -2279,7 +2330,15 @@ static NTSTATUS fill_forest_trust_array(TALLOC_CTX *mem_ctx,
        }
 
        info->count = 2;
-       info->entries = talloc_array(info, struct lsa_ForestTrustRecord *, 2);
+
+       become_root();
+       status = pdb_enum_upn_suffixes(info, &num_suffixes, &upn_suffixes);
+       unbecome_root();
+       if (NT_STATUS_IS_OK(status) && (num_suffixes > 0)) {
+               info->count += num_suffixes;
+       }
+
+       info->entries = talloc_array(info, struct lsa_ForestTrustRecord *, info->count);
        if (info->entries == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -2297,6 +2356,21 @@ static NTSTATUS fill_forest_trust_array(TALLOC_CTX *mem_ctx,
 
        info->entries[0] = e;
 
+       if (num_suffixes > 0) {
+               for (i = 0; i < num_suffixes ; i++) {
+                       e = talloc(info, struct lsa_ForestTrustRecord);
+                       if (e == NULL) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+
+                       e->flags = 0;
+                       e->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME;
+                       e->time = 0; /* so far always 0 in traces. */
+                       e->forest_trust_data.top_level_name.string = upn_suffixes[i];
+                       info->entries[1 + i] = e;
+               }
+       }
+
        e = talloc(info, struct lsa_ForestTrustRecord);
        if (e == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -2315,11 +2389,75 @@ static NTSTATUS fill_forest_trust_array(TALLOC_CTX *mem_ctx,
        domain_info->netbios_domain_name.string = talloc_steal(info,
                                                               dom_info->name);
 
-       info->entries[1] = e;
+       info->entries[info->count - 1] = e;
 
        return NT_STATUS_OK;
 }
 
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsRGetForestTrustInformation(struct pipes_struct *p,
+                                         struct netr_DsRGetForestTrustInformation *r)
+{
+       NTSTATUS status;
+       struct lsa_ForestTrustInformation *info, **info_ptr;
+
+       if (!(p->pipe_bound && (p->auth.auth_type != DCERPC_AUTH_TYPE_NONE)
+                      && (p->auth.auth_level != DCERPC_AUTH_LEVEL_NONE))) {
+               p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
+               return WERR_ACCESS_DENIED;
+       }
+
+       if (r->in.flags & (~DS_GFTI_UPDATE_TDO)) {
+               p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+               return WERR_INVALID_FLAGS;
+       }
+
+       if ((r->in.flags & DS_GFTI_UPDATE_TDO) && (lp_server_role() != ROLE_DOMAIN_PDC)) {
+               p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+               return WERR_NERR_NOTPRIMARY;
+       }
+
+       if ((r->in.trusted_domain_name == NULL) && (r->in.flags & DS_GFTI_UPDATE_TDO)) {
+               p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+               return WERR_INVALID_PARAMETER;
+       }
+
+       /* retrieve forest trust information and stop further processing */
+       if (r->in.trusted_domain_name == NULL) {
+               info_ptr = talloc(p->mem_ctx, struct lsa_ForestTrustInformation *);
+               if (info_ptr == NULL) {
+                       p->fault_state = DCERPC_FAULT_CANT_PERFORM;
+                       return WERR_NOMEM;
+               }
+               info = talloc_zero(info_ptr, struct lsa_ForestTrustInformation);
+               if (info == NULL) {
+                       p->fault_state = DCERPC_FAULT_CANT_PERFORM;
+                       return WERR_NOMEM;
+               }
+
+               /* Fill forest trust information and expand UPN suffixes list */
+               status = fill_forest_trust_array(p->mem_ctx, info);
+               if (!NT_STATUS_IS_OK(status)) {
+                       p->fault_state = DCERPC_FAULT_CANT_PERFORM;
+                       return WERR_NOMEM;
+               }
+
+               *info_ptr = info;
+               r->out.forest_trust_info = info_ptr;
+
+               return WERR_OK;
+
+       }
+
+       /* TODO: implement remaining parts of DsrGetForestTrustInformation (opnum 43)
+        *       when trusted_domain_name is not NULL */
+
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+       return WERR_NOT_SUPPORTED;
+}
+
 /****************************************************************
  _netr_GetForestTrustInformation
 ****************************************************************/
@@ -2334,7 +2472,7 @@ NTSTATUS _netr_GetForestTrustInformation(struct pipes_struct *p,
 
        /* TODO: check server name */
 
-       lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_context());
+       lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers());
        if (lp_ctx == NULL) {
                DEBUG(0, ("loadparm_init_s3 failed\n"));
                return NT_STATUS_INTERNAL_ERROR;
@@ -2364,6 +2502,7 @@ NTSTATUS _netr_GetForestTrustInformation(struct pipes_struct *p,
                return NT_STATUS_NO_MEMORY;
        }
 
+       /* Fill forest trust information, do expand UPN suffixes list */
        status = fill_forest_trust_array(p->mem_ctx, info);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -2380,7 +2519,7 @@ NTSTATUS _netr_GetForestTrustInformation(struct pipes_struct *p,
 
 static NTSTATUS get_password_from_trustAuth(TALLOC_CTX *mem_ctx,
                                            const DATA_BLOB *trustAuth_blob,
-                                           const DATA_BLOB *session_key,
+                                           struct netlogon_creds_CredentialState *creds,
                                            struct samr_Password *current_pw_enc,
                                            struct samr_Password *previous_pw_enc)
 {
@@ -2403,8 +2542,7 @@ static NTSTATUS get_password_from_trustAuth(TALLOC_CTX *mem_ctx,
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       arcfour_crypt_blob(current_pw_enc->hash, sizeof(current_pw_enc->hash),
-                          session_key);
+       netlogon_creds_des_encrypt(creds, current_pw_enc);
 
        if (trustAuth.previous.count != 0 &&
            trustAuth.previous.array[0].AuthType == TRUST_AUTH_TYPE_CLEAR) {
@@ -2414,8 +2552,8 @@ static NTSTATUS get_password_from_trustAuth(TALLOC_CTX *mem_ctx,
        } else {
                mdfour(previous_pw_enc->hash, NULL, 0);
        }
-       arcfour_crypt_blob(previous_pw_enc->hash, sizeof(previous_pw_enc->hash),
-                          session_key);
+
+       netlogon_creds_des_encrypt(creds, previous_pw_enc);
 
        return NT_STATUS_OK;
 }
@@ -2437,10 +2575,9 @@ NTSTATUS _netr_ServerGetTrustInfo(struct pipes_struct *p,
        DATA_BLOB trustAuth_blob;
        struct samr_Password *new_owf_enc;
        struct samr_Password *old_owf_enc;
-       DATA_BLOB session_key;
        struct loadparm_context *lp_ctx;
 
-       lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_context());
+       lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers());
        if (lp_ctx == NULL) {
                DEBUG(0, ("loadparm_init_s3 failed\n"));
                return NT_STATUS_INTERNAL_ERROR;
@@ -2525,10 +2662,8 @@ NTSTATUS _netr_ServerGetTrustInfo(struct pipes_struct *p,
                        trustAuth_blob = td->trust_auth_outgoing;
                }
 
-               session_key.data = creds->session_key;
-               session_key.length = sizeof(creds->session_key);
                status = get_password_from_trustAuth(p->mem_ctx, &trustAuth_blob,
-                                                    &session_key,
+                                                    creds,
                                                     new_owf_enc, old_owf_enc);
 
                if (!NT_STATUS_IS_OK(status)) {
@@ -2554,7 +2689,7 @@ NTSTATUS _netr_ServerGetTrustInfo(struct pipes_struct *p,
 NTSTATUS _netr_Unused47(struct pipes_struct *p,
                        struct netr_Unused47 *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return NT_STATUS_NOT_IMPLEMENTED;
 }
 
@@ -2564,6 +2699,6 @@ NTSTATUS _netr_Unused47(struct pipes_struct *p,
 NTSTATUS _netr_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
                                                 struct netr_DsrUpdateReadOnlyServerDnsRecords *r)
 {
-       p->rng_fault_state = true;
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
        return NT_STATUS_NOT_IMPLEMENTED;
 }