LCOV - code coverage report
Current view: top level - libcli/auth - netlogon_creds_cli.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 654 1873 34.9 %
Date: 2024-06-13 04:01:37 Functions: 39 82 47.6 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    module to store/fetch session keys for the schannel client
       5             : 
       6             :    Copyright (C) Stefan Metzmacher 2013
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "system/filesys.h"
      24             : #include <tevent.h>
      25             : #include "lib/util/tevent_ntstatus.h"
      26             : #include "lib/dbwrap/dbwrap.h"
      27             : #include "lib/dbwrap/dbwrap_rbt.h"
      28             : #include "lib/util/util_tdb.h"
      29             : #include "libcli/security/security.h"
      30             : #include "../lib/param/param.h"
      31             : #include "../libcli/auth/schannel.h"
      32             : #include "../librpc/gen_ndr/ndr_schannel.h"
      33             : #include "../librpc/gen_ndr/ndr_netlogon_c.h"
      34             : #include "../librpc/gen_ndr/ndr_netlogon.h"
      35             : #include "../librpc/gen_ndr/server_id.h"
      36             : #include "netlogon_creds_cli.h"
      37             : #include "source3/include/messages.h"
      38             : #include "source3/include/g_lock.h"
      39             : #include "libds/common/roles.h"
      40             : #include "lib/crypto/md4.h"
      41             : #include "auth/credentials/credentials.h"
      42             : #include "lib/param/loadparm.h"
      43             : 
      44             : struct netlogon_creds_cli_locked_state;
      45             : 
      46             : struct netlogon_creds_cli_context {
      47             :         struct {
      48             :                 const char *computer;
      49             :                 const char *account;
      50             :                 uint32_t proposed_flags;
      51             :                 uint32_t required_flags;
      52             :                 enum netr_SchannelType type;
      53             :                 enum dcerpc_AuthLevel auth_level;
      54             :         } client;
      55             : 
      56             :         struct {
      57             :                 const char *computer;
      58             :                 const char *netbios_domain;
      59             :                 const char *dns_domain;
      60             :                 uint32_t cached_flags;
      61             :                 bool try_validation6;
      62             :                 bool try_logon_ex;
      63             :                 bool try_logon_with;
      64             :         } server;
      65             : 
      66             :         struct {
      67             :                 const char *key_name;
      68             :                 TDB_DATA key_data;
      69             :                 struct db_context *ctx;
      70             :                 struct g_lock_ctx *g_ctx;
      71             :                 struct netlogon_creds_cli_locked_state *locked_state;
      72             :                 enum netlogon_creds_cli_lck_type lock;
      73             :         } db;
      74             : };
      75             : 
      76             : struct netlogon_creds_cli_locked_state {
      77             :         struct netlogon_creds_cli_context *context;
      78             :         bool is_glocked;
      79             :         struct netlogon_creds_CredentialState *creds;
      80             : };
      81             : 
      82           9 : static int netlogon_creds_cli_locked_state_destructor(
      83             :                 struct netlogon_creds_cli_locked_state *state)
      84             : {
      85           9 :         struct netlogon_creds_cli_context *context = state->context;
      86             : 
      87           9 :         if (context == NULL) {
      88           0 :                 return 0;
      89             :         }
      90             : 
      91           9 :         if (context->db.locked_state == state) {
      92           9 :                 context->db.locked_state = NULL;
      93             :         }
      94             : 
      95           9 :         if (state->is_glocked) {
      96           9 :                 g_lock_unlock(context->db.g_ctx,
      97             :                               string_term_tdb_data(context->db.key_name));
      98             :         }
      99             : 
     100           9 :         return 0;
     101             : }
     102             : 
     103          61 : static NTSTATUS netlogon_creds_cli_context_common(
     104             :                                 const char *client_computer,
     105             :                                 const char *client_account,
     106             :                                 enum netr_SchannelType type,
     107             :                                 enum dcerpc_AuthLevel auth_level,
     108             :                                 uint32_t proposed_flags,
     109             :                                 uint32_t required_flags,
     110             :                                 const char *server_computer,
     111             :                                 const char *server_netbios_domain,
     112             :                                 const char *server_dns_domain,
     113             :                                 TALLOC_CTX *mem_ctx,
     114             :                                 struct netlogon_creds_cli_context **_context)
     115             : {
     116          61 :         struct netlogon_creds_cli_context *context = NULL;
     117          61 :         char *_key_name = NULL;
     118             :         size_t server_netbios_name_len;
     119          61 :         char *p = NULL;
     120             : 
     121          61 :         *_context = NULL;
     122             : 
     123          61 :         context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
     124          61 :         if (context == NULL) {
     125           0 :                 return NT_STATUS_NO_MEMORY;
     126             :         }
     127             : 
     128          61 :         context->client.computer = talloc_strdup(context, client_computer);
     129          61 :         if (context->client.computer == NULL) {
     130           0 :                 TALLOC_FREE(context);
     131           0 :                 return NT_STATUS_NO_MEMORY;
     132             :         }
     133             : 
     134          61 :         context->client.account = talloc_strdup(context, client_account);
     135          61 :         if (context->client.account == NULL) {
     136           0 :                 TALLOC_FREE(context);
     137           0 :                 return NT_STATUS_NO_MEMORY;
     138             :         }
     139             : 
     140          61 :         context->client.proposed_flags = proposed_flags;
     141          61 :         context->client.required_flags = required_flags;
     142          61 :         context->client.type = type;
     143          61 :         context->client.auth_level = auth_level;
     144             : 
     145          61 :         context->server.computer = talloc_strdup(context, server_computer);
     146          61 :         if (context->server.computer == NULL) {
     147           0 :                 TALLOC_FREE(context);
     148           0 :                 return NT_STATUS_NO_MEMORY;
     149             :         }
     150             : 
     151          61 :         context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
     152          61 :         if (context->server.netbios_domain == NULL) {
     153           0 :                 TALLOC_FREE(context);
     154           0 :                 return NT_STATUS_NO_MEMORY;
     155             :         }
     156             : 
     157          61 :         context->server.dns_domain = talloc_strdup(context, server_dns_domain);
     158          61 :         if (context->server.dns_domain == NULL) {
     159           0 :                 TALLOC_FREE(context);
     160           0 :                 return NT_STATUS_NO_MEMORY;
     161             :         }
     162             : 
     163             :         /*
     164             :          * TODO:
     165             :          * Force the callers to provide a unique
     166             :          * value for server_computer and use this directly.
     167             :          *
     168             :          * For now we have to deal with
     169             :          * "HOSTNAME" vs. "hostname.example.com".
     170             :          */
     171             : 
     172          61 :         p = strchr(server_computer, '.');
     173          61 :         if (p != NULL) {
     174          31 :                 server_netbios_name_len = p-server_computer;
     175             :         } else {
     176          30 :                 server_netbios_name_len = strlen(server_computer);
     177             :         }
     178             : 
     179          61 :         _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
     180             :                                     client_computer,
     181             :                                     client_account,
     182             :                                     (int)server_netbios_name_len,
     183             :                                     server_computer,
     184             :                                     server_netbios_domain);
     185          61 :         if (_key_name == NULL) {
     186           0 :                 TALLOC_FREE(context);
     187           0 :                 return NT_STATUS_NO_MEMORY;
     188             :         }
     189             : 
     190          61 :         context->db.key_name = talloc_strdup_upper(context, _key_name);
     191          61 :         TALLOC_FREE(_key_name);
     192          61 :         if (context->db.key_name == NULL) {
     193           0 :                 TALLOC_FREE(context);
     194           0 :                 return NT_STATUS_NO_MEMORY;
     195             :         }
     196             : 
     197          61 :         context->db.key_data = string_term_tdb_data(context->db.key_name);
     198             : 
     199          61 :         *_context = context;
     200          61 :         return NT_STATUS_OK;
     201             : }
     202             : 
     203             : static struct db_context *netlogon_creds_cli_global_db;
     204             : 
     205         126 : NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx,
     206             :                                           struct db_context **db)
     207             : {
     208         126 :         netlogon_creds_cli_warn_options(lp_ctx);
     209             : 
     210         126 :         if (netlogon_creds_cli_global_db != NULL) {
     211           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     212             :         }
     213             : 
     214         126 :         netlogon_creds_cli_global_db = talloc_move(NULL, db);
     215         126 :         return NT_STATUS_OK;
     216             : }
     217             : 
     218          61 : NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
     219             : {
     220             :         char *fname;
     221             :         struct db_context *global_db;
     222             :         int hash_size, tdb_flags;
     223             : 
     224          61 :         netlogon_creds_cli_warn_options(lp_ctx);
     225             : 
     226          61 :         if (netlogon_creds_cli_global_db != NULL) {
     227          61 :                 return NT_STATUS_OK;
     228             :         }
     229             : 
     230           0 :         fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
     231           0 :         if (fname == NULL) {
     232           0 :                 return NT_STATUS_NO_MEMORY;
     233             :         }
     234             : 
     235           0 :         hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
     236           0 :         tdb_flags = lpcfg_tdb_flags(
     237             :                 lp_ctx,
     238             :                 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH);
     239             : 
     240           0 :         global_db = dbwrap_local_open(
     241             :                 NULL,
     242             :                 fname,
     243             :                 hash_size,
     244             :                 tdb_flags,
     245             :                 O_RDWR|O_CREAT,
     246             :                 0600,
     247             :                 DBWRAP_LOCK_ORDER_2,
     248             :                 DBWRAP_FLAG_NONE);
     249           0 :         if (global_db == NULL) {
     250           0 :                 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
     251             :                          fname, strerror(errno)));
     252           0 :                 talloc_free(fname);
     253           0 :                 return NT_STATUS_NO_MEMORY;
     254             :         }
     255           0 :         TALLOC_FREE(fname);
     256             : 
     257           0 :         netlogon_creds_cli_global_db = global_db;
     258           0 :         return NT_STATUS_OK;
     259             : }
     260             : 
     261        5743 : void netlogon_creds_cli_close_global_db(void)
     262             : {
     263        5743 :         TALLOC_FREE(netlogon_creds_cli_global_db);
     264        5743 : }
     265             : 
     266         237 : void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx)
     267             : {
     268         237 :         bool global_reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
     269         237 :         bool global_require_strong_key = lpcfg_require_strong_key(lp_ctx);
     270         237 :         int global_client_schannel = lpcfg_client_schannel(lp_ctx);
     271         237 :         bool global_seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
     272         237 :         int global_kerberos_enctypes = lpcfg_kerberos_encryption_types(lp_ctx);
     273             :         static bool warned_global_reject_md5_servers = false;
     274             :         static bool warned_global_require_strong_key = false;
     275             :         static bool warned_global_client_schannel = false;
     276             :         static bool warned_global_seal_secure_channel = false;
     277             :         static bool warned_global_kerberos_encryption_types = false;
     278             :         static int warned_global_pid = 0;
     279         237 :         int current_pid = tevent_cached_getpid();
     280             : 
     281         237 :         if (warned_global_pid != current_pid) {
     282         127 :                 warned_global_reject_md5_servers = false;
     283         127 :                 warned_global_require_strong_key = false;
     284         127 :                 warned_global_client_schannel = false;
     285         127 :                 warned_global_seal_secure_channel = false;
     286         127 :                 warned_global_kerberos_encryption_types = false;
     287         127 :                 warned_global_pid = current_pid;
     288             :         }
     289             : 
     290         237 :         if (!global_reject_md5_servers && !warned_global_reject_md5_servers) {
     291             :                 /*
     292             :                  * We want admins to notice their misconfiguration!
     293             :                  */
     294           0 :                 DBG_ERR("CVE-2022-38023 (and others): "
     295             :                         "Please configure 'reject md5 servers = yes' (the default), "
     296             :                         "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
     297           0 :                 warned_global_reject_md5_servers = true;
     298             :         }
     299             : 
     300         237 :         if (!global_require_strong_key && !warned_global_require_strong_key) {
     301             :                 /*
     302             :                  * We want admins to notice their misconfiguration!
     303             :                  */
     304           0 :                 DBG_ERR("CVE-2022-38023 (and others): "
     305             :                         "Please configure 'require strong key = yes' (the default), "
     306             :                         "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
     307           0 :                 warned_global_require_strong_key = true;
     308             :         }
     309             : 
     310         237 :         if (global_client_schannel != true && !warned_global_client_schannel) {
     311             :                 /*
     312             :                  * We want admins to notice their misconfiguration!
     313             :                  */
     314           0 :                 DBG_ERR("CVE-2022-38023 (and others): "
     315             :                         "Please configure 'client schannel = yes' (the default), "
     316             :                         "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
     317           0 :                 warned_global_client_schannel = true;
     318             :         }
     319             : 
     320         237 :         if (!global_seal_secure_channel && !warned_global_seal_secure_channel) {
     321             :                 /*
     322             :                  * We want admins to notice their misconfiguration!
     323             :                  */
     324           0 :                 DBG_ERR("CVE-2022-38023 (and others): "
     325             :                         "Please configure 'winbind sealed pipes = yes' (the default), "
     326             :                         "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
     327           0 :                 warned_global_seal_secure_channel = true;
     328             :         }
     329             : 
     330         237 :         if (global_kerberos_enctypes == KERBEROS_ETYPES_LEGACY &&
     331           0 :             !warned_global_kerberos_encryption_types)
     332             :         {
     333             :                 /*
     334             :                  * We want admins to notice their misconfiguration!
     335             :                  */
     336           0 :                 DBG_ERR("CVE-2022-37966: "
     337             :                         "Please void 'kerberos encryption types = legacy', "
     338             :                         "See https://bugzilla.samba.org/show_bug.cgi?id=15237\n");
     339           0 :                 warned_global_kerberos_encryption_types = true;
     340             :         }
     341         237 : }
     342             : 
     343          61 : NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
     344             :                                 struct messaging_context *msg_ctx,
     345             :                                 const char *client_account,
     346             :                                 enum netr_SchannelType type,
     347             :                                 const char *server_computer,
     348             :                                 const char *server_netbios_domain,
     349             :                                 const char *server_dns_domain,
     350             :                                 TALLOC_CTX *mem_ctx,
     351             :                                 struct netlogon_creds_cli_context **_context)
     352             : {
     353          61 :         TALLOC_CTX *frame = talloc_stackframe();
     354             :         NTSTATUS status;
     355          61 :         struct netlogon_creds_cli_context *context = NULL;
     356             :         const char *client_computer;
     357             :         uint32_t proposed_flags;
     358          61 :         uint32_t required_flags = 0;
     359          61 :         bool reject_md5_servers = true;
     360          61 :         bool require_strong_key = true;
     361          61 :         int require_sign_or_seal = true;
     362          61 :         bool seal_secure_channel = true;
     363          61 :         enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
     364          61 :         bool neutralize_nt4_emulation = false;
     365             : 
     366          61 :         *_context = NULL;
     367             : 
     368          61 :         if (msg_ctx == NULL) {
     369           0 :                 TALLOC_FREE(frame);
     370           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     371             :         }
     372             : 
     373          61 :         client_computer = lpcfg_netbios_name(lp_ctx);
     374          61 :         if (strlen(client_computer) > 15) {
     375           0 :                 TALLOC_FREE(frame);
     376           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     377             :         }
     378             : 
     379             :         /*
     380             :          * allow overwrite per domain
     381             :          * reject md5 servers:<netbios_domain>
     382             :          */
     383          61 :         reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
     384          61 :         reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
     385             :                                              "reject md5 servers",
     386             :                                              server_netbios_domain,
     387             :                                              reject_md5_servers);
     388             : 
     389             :         /*
     390             :          * allow overwrite per domain
     391             :          * require strong key:<netbios_domain>
     392             :          */
     393          61 :         require_strong_key = lpcfg_require_strong_key(lp_ctx);
     394          61 :         require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
     395             :                                              "require strong key",
     396             :                                              server_netbios_domain,
     397             :                                              require_strong_key);
     398             : 
     399             :         /*
     400             :          * allow overwrite per domain
     401             :          * client schannel:<netbios_domain>
     402             :          */
     403          61 :         require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
     404          61 :         require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
     405             :                                               "client schannel",
     406             :                                               server_netbios_domain,
     407             :                                               require_sign_or_seal);
     408             : 
     409             :         /*
     410             :          * allow overwrite per domain
     411             :          * winbind sealed pipes:<netbios_domain>
     412             :          */
     413          61 :         seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
     414          61 :         seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
     415             :                                               "winbind sealed pipes",
     416             :                                               server_netbios_domain,
     417             :                                               seal_secure_channel);
     418             : 
     419             :         /*
     420             :          * allow overwrite per domain
     421             :          * neutralize nt4 emulation:<netbios_domain>
     422             :          */
     423          61 :         neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
     424          61 :         neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
     425             :                                                    "neutralize nt4 emulation",
     426             :                                                    server_netbios_domain,
     427             :                                                    neutralize_nt4_emulation);
     428             : 
     429          61 :         proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
     430          61 :         proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
     431             : 
     432          61 :         switch (type) {
     433          44 :         case SEC_CHAN_WKSTA:
     434          44 :                 if (lpcfg_security(lp_ctx) == SEC_ADS) {
     435             :                         /*
     436             :                          * AD domains should be secure
     437             :                          */
     438          40 :                         required_flags |= NETLOGON_NEG_PASSWORD_SET2;
     439          40 :                         require_sign_or_seal = true;
     440          40 :                         require_strong_key = true;
     441             :                 }
     442          44 :                 break;
     443             : 
     444           0 :         case SEC_CHAN_DOMAIN:
     445           0 :                 break;
     446             : 
     447           0 :         case SEC_CHAN_DNS_DOMAIN:
     448             :                 /*
     449             :                  * AD domains should be secure
     450             :                  */
     451           0 :                 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
     452           0 :                 require_sign_or_seal = true;
     453           0 :                 require_strong_key = true;
     454           0 :                 neutralize_nt4_emulation = true;
     455           0 :                 break;
     456             : 
     457          11 :         case SEC_CHAN_BDC:
     458          11 :                 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
     459          11 :                 require_sign_or_seal = true;
     460          11 :                 require_strong_key = true;
     461          11 :                 break;
     462             : 
     463           6 :         case SEC_CHAN_RODC:
     464           6 :                 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
     465           6 :                 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
     466           6 :                 require_sign_or_seal = true;
     467           6 :                 require_strong_key = true;
     468           6 :                 neutralize_nt4_emulation = true;
     469           6 :                 break;
     470             : 
     471           0 :         default:
     472           0 :                 TALLOC_FREE(frame);
     473           0 :                 return NT_STATUS_INVALID_PARAMETER;
     474             :         }
     475             : 
     476          61 :         if (neutralize_nt4_emulation) {
     477           6 :                 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
     478             :         }
     479             : 
     480          61 :         if (require_sign_or_seal) {
     481          61 :                 required_flags |= NETLOGON_NEG_ARCFOUR;
     482          61 :                 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
     483             :         } else {
     484           0 :                 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
     485             :         }
     486             : 
     487          61 :         if (reject_md5_servers) {
     488          61 :                 required_flags |= NETLOGON_NEG_ARCFOUR;
     489          61 :                 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
     490          61 :                 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
     491          61 :                 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
     492             :         }
     493             : 
     494          61 :         if (require_strong_key) {
     495          61 :                 required_flags |= NETLOGON_NEG_ARCFOUR;
     496          61 :                 required_flags |= NETLOGON_NEG_STRONG_KEYS;
     497          61 :                 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
     498             :         }
     499             : 
     500             :         /*
     501             :          * If weak crypto is disabled, do not announce that we support RC4 and
     502             :          * require AES.
     503             :          */
     504          61 :         if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
     505           0 :                 required_flags &= ~NETLOGON_NEG_ARCFOUR;
     506           0 :                 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
     507           0 :                 proposed_flags &= ~NETLOGON_NEG_ARCFOUR;
     508           0 :                 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
     509             :         }
     510             : 
     511          61 :         proposed_flags |= required_flags;
     512             : 
     513          61 :         if (seal_secure_channel) {
     514          61 :                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
     515             :         } else {
     516           0 :                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
     517             :         }
     518             : 
     519          61 :         status = netlogon_creds_cli_context_common(client_computer,
     520             :                                                    client_account,
     521             :                                                    type,
     522             :                                                    auth_level,
     523             :                                                    proposed_flags,
     524             :                                                    required_flags,
     525             :                                                    server_computer,
     526             :                                                    server_netbios_domain,
     527             :                                                    "",
     528             :                                                    mem_ctx,
     529             :                                                    &context);
     530          61 :         if (!NT_STATUS_IS_OK(status)) {
     531           0 :                 TALLOC_FREE(frame);
     532           0 :                 return status;
     533             :         }
     534             : 
     535          61 :         context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
     536          61 :         if (context->db.g_ctx == NULL) {
     537           0 :                 TALLOC_FREE(context);
     538           0 :                 TALLOC_FREE(frame);
     539           0 :                 return NT_STATUS_NO_MEMORY;
     540             :         }
     541             : 
     542          61 :         status = netlogon_creds_cli_open_global_db(lp_ctx);
     543          61 :         if (!NT_STATUS_IS_OK(status)) {
     544           0 :                 TALLOC_FREE(context);
     545           0 :                 TALLOC_FREE(frame);
     546           0 :                 return NT_STATUS_NO_MEMORY;
     547             :         }
     548             : 
     549          61 :         context->db.ctx = netlogon_creds_cli_global_db;
     550          61 :         *_context = context;
     551          61 :         TALLOC_FREE(frame);
     552          61 :         return NT_STATUS_OK;
     553             : }
     554             : 
     555          51 : NTSTATUS netlogon_creds_bind_cli_credentials(
     556             :         struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
     557             :         struct cli_credentials **pcli_creds)
     558             : {
     559             :         struct cli_credentials *cli_creds;
     560             :         struct netlogon_creds_CredentialState *ncreds;
     561             :         NTSTATUS status;
     562             : 
     563          51 :         cli_creds = cli_credentials_init(mem_ctx);
     564          51 :         if (cli_creds == NULL) {
     565           0 :                 return NT_STATUS_NO_MEMORY;
     566             :         }
     567          51 :         cli_credentials_set_secure_channel_type(cli_creds,
     568             :                                                 context->client.type);
     569          51 :         cli_credentials_set_username(cli_creds, context->client.account,
     570             :                                      CRED_SPECIFIED);
     571          51 :         cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
     572             :                                    CRED_SPECIFIED);
     573          51 :         cli_credentials_set_realm(cli_creds, context->server.dns_domain,
     574             :                                   CRED_SPECIFIED);
     575             : 
     576          51 :         status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
     577          51 :         if (!NT_STATUS_IS_OK(status)) {
     578           0 :                 TALLOC_FREE(cli_creds);
     579           0 :                 return status;
     580             :         }
     581          51 :         cli_credentials_set_netlogon_creds(cli_creds, ncreds);
     582             : 
     583          51 :         *pcli_creds = cli_creds;
     584          51 :         return NT_STATUS_OK;
     585             : }
     586             : 
     587           0 : char *netlogon_creds_cli_debug_string(
     588             :                 const struct netlogon_creds_cli_context *context,
     589             :                 TALLOC_CTX *mem_ctx)
     590             : {
     591           0 :         return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
     592           0 :                                context->db.key_name);
     593             : }
     594             : 
     595          51 : enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
     596             :                 struct netlogon_creds_cli_context *context)
     597             : {
     598          51 :         return context->client.auth_level;
     599             : }
     600             : 
     601         259 : static bool netlogon_creds_cli_downgraded(uint32_t negotiated_flags,
     602             :                                           uint32_t proposed_flags,
     603             :                                           uint32_t required_flags)
     604             : {
     605         259 :         uint32_t req_flags = required_flags;
     606             :         uint32_t tmp_flags;
     607             : 
     608         259 :         req_flags = required_flags;
     609         434 :         if ((negotiated_flags & NETLOGON_NEG_SUPPORTS_AES) &&
     610         259 :             (proposed_flags & NETLOGON_NEG_SUPPORTS_AES))
     611             :         {
     612         259 :                 req_flags &= ~NETLOGON_NEG_ARCFOUR|NETLOGON_NEG_STRONG_KEYS;
     613             :         }
     614             : 
     615         259 :         tmp_flags = negotiated_flags;
     616         259 :         tmp_flags &= req_flags;
     617         259 :         if (tmp_flags != req_flags) {
     618           0 :                 return true;
     619             :         }
     620             : 
     621         259 :         return false;
     622             : }
     623             : 
     624             : struct netlogon_creds_cli_fetch_state {
     625             :         TALLOC_CTX *mem_ctx;
     626             :         struct netlogon_creds_CredentialState *creds;
     627             :         uint32_t proposed_flags;
     628             :         uint32_t required_flags;
     629             :         NTSTATUS status;
     630             : };
     631             : 
     632         222 : static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
     633             :                                             void *private_data)
     634             : {
     635         222 :         struct netlogon_creds_cli_fetch_state *state =
     636             :                 (struct netlogon_creds_cli_fetch_state *)private_data;
     637             :         enum ndr_err_code ndr_err;
     638             :         DATA_BLOB blob;
     639             :         bool downgraded;
     640             : 
     641         222 :         state->creds = talloc_zero(state->mem_ctx,
     642             :                                    struct netlogon_creds_CredentialState);
     643         222 :         if (state->creds == NULL) {
     644           0 :                 state->status = NT_STATUS_NO_MEMORY;
     645           0 :                 return;
     646             :         }
     647             : 
     648         222 :         blob.data = data.dptr;
     649         222 :         blob.length = data.dsize;
     650             : 
     651         222 :         ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
     652             :                 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
     653         222 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     654           0 :                 TALLOC_FREE(state->creds);
     655           0 :                 state->status = ndr_map_error2ntstatus(ndr_err);
     656           0 :                 return;
     657             :         }
     658             : 
     659         222 :         if (DEBUGLEVEL >= 10) {
     660           0 :                 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
     661             :         }
     662             : 
     663         373 :         downgraded = netlogon_creds_cli_downgraded(
     664         222 :                         state->creds->negotiate_flags,
     665             :                         state->proposed_flags,
     666             :                         state->required_flags);
     667         222 :         if (downgraded) {
     668           0 :                 TALLOC_FREE(state->creds);
     669           0 :                 state->status = NT_STATUS_DOWNGRADE_DETECTED;
     670           0 :                 return;
     671             :         }
     672             : 
     673         222 :         state->status = NT_STATUS_OK;
     674             : }
     675             : 
     676             : static NTSTATUS netlogon_creds_cli_get_internal(
     677             :         struct netlogon_creds_cli_context *context,
     678             :         TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
     679             : 
     680         196 : NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
     681             :                                 TALLOC_CTX *mem_ctx,
     682             :                                 struct netlogon_creds_CredentialState **_creds)
     683             : {
     684             :         NTSTATUS status;
     685             :         struct netlogon_creds_CredentialState *creds;
     686             : 
     687         196 :         *_creds = NULL;
     688             : 
     689         196 :         status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
     690         196 :         if (!NT_STATUS_IS_OK(status)) {
     691          28 :                 return status;
     692             :         }
     693             : 
     694             :         /*
     695             :          * mark it as invalid for step operations.
     696             :          */
     697         168 :         creds->sequence = 0;
     698         168 :         creds->seed = (struct netr_Credential) {{0}};
     699         168 :         creds->client = (struct netr_Credential) {{0}};
     700         168 :         creds->server = (struct netr_Credential) {{0}};
     701             : 
     702         168 :         *_creds = creds;
     703         168 :         return NT_STATUS_OK;
     704             : }
     705             : 
     706           0 : bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
     707             :                         const struct netlogon_creds_CredentialState *creds1)
     708             : {
     709           0 :         TALLOC_CTX *frame = talloc_stackframe();
     710             :         struct netlogon_creds_CredentialState *creds2;
     711             :         DATA_BLOB blob1;
     712             :         DATA_BLOB blob2;
     713             :         NTSTATUS status;
     714             :         enum ndr_err_code ndr_err;
     715             :         bool equal;
     716             : 
     717           0 :         status = netlogon_creds_cli_get(context, frame, &creds2);
     718           0 :         if (!NT_STATUS_IS_OK(status)) {
     719           0 :                 TALLOC_FREE(frame);
     720           0 :                 return false;
     721             :         }
     722             : 
     723           0 :         ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
     724             :                 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
     725           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     726           0 :                 TALLOC_FREE(frame);
     727           0 :                 return false;
     728             :         }
     729             : 
     730           0 :         ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
     731             :                 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
     732           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     733           0 :                 TALLOC_FREE(frame);
     734           0 :                 return false;
     735             :         }
     736             : 
     737           0 :         equal = data_blob_equal_const_time(&blob1, &blob2);
     738             : 
     739           0 :         TALLOC_FREE(frame);
     740             : 
     741           0 :         return equal;
     742             : }
     743             : 
     744          54 : static NTSTATUS netlogon_creds_cli_store_internal(
     745             :         struct netlogon_creds_cli_context *context,
     746             :         struct netlogon_creds_CredentialState *creds)
     747             : {
     748             :         NTSTATUS status;
     749             :         enum ndr_err_code ndr_err;
     750             :         DATA_BLOB blob;
     751             :         TDB_DATA data;
     752             : 
     753          54 :         if (DEBUGLEVEL >= 10) {
     754           0 :                 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
     755             :         }
     756             : 
     757          54 :         ndr_err = ndr_push_struct_blob(&blob, creds, creds,
     758             :                 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
     759          54 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     760           0 :                 status = ndr_map_error2ntstatus(ndr_err);
     761           0 :                 return status;
     762             :         }
     763             : 
     764          54 :         data.dptr = blob.data;
     765          54 :         data.dsize = blob.length;
     766             : 
     767          54 :         status = dbwrap_store(context->db.ctx,
     768             :                               context->db.key_data,
     769             :                               data, TDB_REPLACE);
     770          54 :         TALLOC_FREE(data.dptr);
     771          54 :         if (!NT_STATUS_IS_OK(status)) {
     772           0 :                 return status;
     773             :         }
     774             : 
     775          54 :         return NT_STATUS_OK;
     776             : }
     777             : 
     778           9 : NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
     779             :                                   struct netlogon_creds_CredentialState *creds)
     780             : {
     781             :         NTSTATUS status;
     782             : 
     783           9 :         if (context->db.locked_state == NULL) {
     784             :                 /*
     785             :                  * this was not the result of netlogon_creds_cli_lock*()
     786             :                  */
     787           0 :                 return NT_STATUS_INVALID_PAGE_PROTECTION;
     788             :         }
     789             : 
     790           9 :         if (context->db.locked_state->creds != creds) {
     791             :                 /*
     792             :                  * this was not the result of netlogon_creds_cli_lock*()
     793             :                  */
     794           0 :                 return NT_STATUS_INVALID_PAGE_PROTECTION;
     795             :         }
     796             : 
     797           9 :         status = netlogon_creds_cli_store_internal(context, creds);
     798           9 :         return status;
     799             : }
     800             : 
     801           0 : static NTSTATUS netlogon_creds_cli_delete_internal(
     802             :         struct netlogon_creds_cli_context *context)
     803             : {
     804             :         NTSTATUS status;
     805           0 :         status = dbwrap_delete(context->db.ctx, context->db.key_data);
     806           0 :         return status;
     807             : }
     808             : 
     809           0 : NTSTATUS netlogon_creds_cli_delete_lck(
     810             :         struct netlogon_creds_cli_context *context)
     811             : {
     812             :         NTSTATUS status;
     813             : 
     814           0 :         if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
     815           0 :                 return NT_STATUS_NOT_LOCKED;
     816             :         }
     817             : 
     818           0 :         status = netlogon_creds_cli_delete_internal(context);
     819           0 :         return status;
     820             : }
     821             : 
     822           0 : NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
     823             :                                    struct netlogon_creds_CredentialState *creds)
     824             : {
     825             :         NTSTATUS status;
     826             : 
     827           0 :         if (context->db.locked_state == NULL) {
     828             :                 /*
     829             :                  * this was not the result of netlogon_creds_cli_lock*()
     830             :                  */
     831           0 :                 return NT_STATUS_INVALID_PAGE_PROTECTION;
     832             :         }
     833             : 
     834           0 :         if (context->db.locked_state->creds != creds) {
     835             :                 /*
     836             :                  * this was not the result of netlogon_creds_cli_lock*()
     837             :                  */
     838           0 :                 return NT_STATUS_INVALID_PAGE_PROTECTION;
     839             :         }
     840             : 
     841           0 :         status = netlogon_creds_cli_delete_internal(context);
     842           0 :         return status;
     843             : }
     844             : 
     845             : struct netlogon_creds_cli_lock_state {
     846             :         struct netlogon_creds_cli_locked_state *locked_state;
     847             :         struct netlogon_creds_CredentialState *creds;
     848             : };
     849             : 
     850             : static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
     851             : 
     852           9 : struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
     853             :                                 struct tevent_context *ev,
     854             :                                 struct netlogon_creds_cli_context *context)
     855             : {
     856             :         struct tevent_req *req;
     857             :         struct netlogon_creds_cli_lock_state *state;
     858             :         struct netlogon_creds_cli_locked_state *locked_state;
     859             :         struct tevent_req *subreq;
     860             : 
     861           9 :         req = tevent_req_create(mem_ctx, &state,
     862             :                                 struct netlogon_creds_cli_lock_state);
     863           9 :         if (req == NULL) {
     864           0 :                 return NULL;
     865             :         }
     866             : 
     867           9 :         if (context->db.locked_state != NULL) {
     868           0 :                 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
     869           0 :                 return tevent_req_post(req, ev);
     870             :         }
     871             : 
     872           9 :         locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
     873           9 :         if (tevent_req_nomem(locked_state, req)) {
     874           0 :                 return tevent_req_post(req, ev);
     875             :         }
     876           9 :         talloc_set_destructor(locked_state,
     877             :                               netlogon_creds_cli_locked_state_destructor);
     878           9 :         locked_state->context = context;
     879             : 
     880           9 :         context->db.locked_state = locked_state;
     881           9 :         state->locked_state = locked_state;
     882             : 
     883           9 :         if (context->db.g_ctx == NULL) {
     884             :                 NTSTATUS status;
     885             : 
     886           0 :                 status = netlogon_creds_cli_get_internal(
     887           0 :                         context, state, &state->creds);
     888           0 :                 if (tevent_req_nterror(req, status)) {
     889           0 :                         return tevent_req_post(req, ev);
     890             :                 }
     891             : 
     892           0 :                 return req;
     893             :         }
     894             : 
     895           9 :         subreq = g_lock_lock_send(state, ev,
     896             :                                   context->db.g_ctx,
     897             :                                   string_term_tdb_data(context->db.key_name),
     898             :                                   G_LOCK_WRITE);
     899           9 :         if (tevent_req_nomem(subreq, req)) {
     900           0 :                 return tevent_req_post(req, ev);
     901             :         }
     902           9 :         tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
     903             : 
     904           9 :         return req;
     905             : }
     906             : 
     907           9 : static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
     908             : {
     909           9 :         struct tevent_req *req =
     910           9 :                 tevent_req_callback_data(subreq,
     911             :                 struct tevent_req);
     912           9 :         struct netlogon_creds_cli_lock_state *state =
     913           9 :                 tevent_req_data(req,
     914             :                 struct netlogon_creds_cli_lock_state);
     915             :         NTSTATUS status;
     916             : 
     917           9 :         status = g_lock_lock_recv(subreq);
     918           9 :         TALLOC_FREE(subreq);
     919           9 :         if (tevent_req_nterror(req, status)) {
     920           0 :                 return;
     921             :         }
     922           9 :         state->locked_state->is_glocked = true;
     923             : 
     924           9 :         status = netlogon_creds_cli_get_internal(state->locked_state->context,
     925             :                                                state, &state->creds);
     926           9 :         if (tevent_req_nterror(req, status)) {
     927           0 :                 return;
     928             :         }
     929           9 :         tevent_req_done(req);
     930             : }
     931             : 
     932         250 : static NTSTATUS netlogon_creds_cli_get_internal(
     933             :         struct netlogon_creds_cli_context *context,
     934             :         TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
     935             : {
     936         588 :         struct netlogon_creds_cli_fetch_state fstate = {
     937             :                 .status = NT_STATUS_INTERNAL_ERROR,
     938         250 :                 .proposed_flags = context->client.proposed_flags,
     939         250 :                 .required_flags = context->client.required_flags,
     940             :         };
     941             :         NTSTATUS status;
     942             : 
     943         250 :         fstate.mem_ctx = mem_ctx;
     944         250 :         status = dbwrap_parse_record(context->db.ctx,
     945             :                                      context->db.key_data,
     946             :                                      netlogon_creds_cli_fetch_parser,
     947             :                                      &fstate);
     948         250 :         if (!NT_STATUS_IS_OK(status)) {
     949          28 :                 return status;
     950             :         }
     951         222 :         if (!NT_STATUS_IS_OK(fstate.status)) {
     952           0 :                 return fstate.status;
     953             :         }
     954             : 
     955         222 :         if (context->server.cached_flags == fstate.creds->negotiate_flags) {
     956         162 :                 *pcreds = fstate.creds;
     957         162 :                 return NT_STATUS_OK;
     958             :         }
     959             : 
     960             :         /*
     961             :          * It is really important to try SamLogonEx here,
     962             :          * because multiple processes can talk to the same
     963             :          * domain controller, without using the credential
     964             :          * chain.
     965             :          *
     966             :          * With a normal SamLogon call, we must keep the
     967             :          * credentials chain updated and intact between all
     968             :          * users of the machine account (which would imply
     969             :          * cross-node communication for every NTLM logon).
     970             :          *
     971             :          * The credentials chain is not per NETLOGON pipe
     972             :          * connection, but globally on the server/client pair
     973             :          * by computer name.
     974             :          *
     975             :          * It's also important to use NetlogonValidationSamInfo4 (6),
     976             :          * because it relies on the rpc transport encryption
     977             :          * and avoids using the global netlogon schannel
     978             :          * session key to en/decrypt secret information
     979             :          * like the user_session_key for network logons.
     980             :          *
     981             :          * [MS-APDS] 3.1.5.2 NTLM Network Logon
     982             :          * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
     983             :          * NETLOGON_NEG_AUTHENTICATED_RPC set together
     984             :          * are the indication that the server supports
     985             :          * NetlogonValidationSamInfo4 (6). And it must only
     986             :          * be used if "SealSecureChannel" is used.
     987             :          *
     988             :          * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
     989             :          * check is done in netlogon_creds_cli_LogonSamLogon*().
     990             :          */
     991             : 
     992          60 :         context->server.cached_flags = fstate.creds->negotiate_flags;
     993          60 :         context->server.try_validation6 = true;
     994          60 :         context->server.try_logon_ex = true;
     995          60 :         context->server.try_logon_with = true;
     996             : 
     997          60 :         if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
     998           0 :                 context->server.try_validation6 = false;
     999           0 :                 context->server.try_logon_ex = false;
    1000             :         }
    1001          60 :         if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
    1002           3 :                 context->server.try_validation6 = false;
    1003             :         }
    1004             : 
    1005          60 :         *pcreds = fstate.creds;
    1006          60 :         return NT_STATUS_OK;
    1007             : }
    1008             : 
    1009           9 : NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
    1010             :                         TALLOC_CTX *mem_ctx,
    1011             :                         struct netlogon_creds_CredentialState **creds)
    1012             : {
    1013           9 :         struct netlogon_creds_cli_lock_state *state =
    1014           9 :                 tevent_req_data(req,
    1015             :                 struct netlogon_creds_cli_lock_state);
    1016             :         NTSTATUS status;
    1017             : 
    1018           9 :         if (tevent_req_is_nterror(req, &status)) {
    1019           0 :                 tevent_req_received(req);
    1020           0 :                 return status;
    1021             :         }
    1022             : 
    1023           9 :         talloc_steal(state->creds, state->locked_state);
    1024           9 :         state->locked_state->creds = state->creds;
    1025           9 :         *creds = talloc_move(mem_ctx, &state->creds);
    1026           9 :         tevent_req_received(req);
    1027           9 :         return NT_STATUS_OK;
    1028             : }
    1029             : 
    1030           0 : NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
    1031             :                         TALLOC_CTX *mem_ctx,
    1032             :                         struct netlogon_creds_CredentialState **creds)
    1033             : {
    1034           0 :         TALLOC_CTX *frame = talloc_stackframe();
    1035             :         struct tevent_context *ev;
    1036             :         struct tevent_req *req;
    1037           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1038             : 
    1039           0 :         ev = samba_tevent_context_init(frame);
    1040           0 :         if (ev == NULL) {
    1041           0 :                 goto fail;
    1042             :         }
    1043           0 :         req = netlogon_creds_cli_lock_send(frame, ev, context);
    1044           0 :         if (req == NULL) {
    1045           0 :                 goto fail;
    1046             :         }
    1047           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1048           0 :                 goto fail;
    1049             :         }
    1050           0 :         status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
    1051           0 :  fail:
    1052           0 :         TALLOC_FREE(frame);
    1053           0 :         return status;
    1054             : }
    1055             : 
    1056             : struct netlogon_creds_cli_lck {
    1057             :         struct netlogon_creds_cli_context *context;
    1058             : };
    1059             : 
    1060             : struct netlogon_creds_cli_lck_state {
    1061             :         struct netlogon_creds_cli_lck *lck;
    1062             :         enum netlogon_creds_cli_lck_type type;
    1063             : };
    1064             : 
    1065             : static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
    1066             : static int netlogon_creds_cli_lck_destructor(
    1067             :         struct netlogon_creds_cli_lck *lck);
    1068             : 
    1069         110 : struct tevent_req *netlogon_creds_cli_lck_send(
    1070             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
    1071             :         struct netlogon_creds_cli_context *context,
    1072             :         enum netlogon_creds_cli_lck_type type)
    1073             : {
    1074             :         struct tevent_req *req, *subreq;
    1075             :         struct netlogon_creds_cli_lck_state *state;
    1076             :         enum g_lock_type gtype;
    1077             : 
    1078         110 :         req = tevent_req_create(mem_ctx, &state,
    1079             :                                 struct netlogon_creds_cli_lck_state);
    1080         110 :         if (req == NULL) {
    1081           0 :                 return NULL;
    1082             :         }
    1083             : 
    1084         110 :         if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
    1085           0 :                 DBG_DEBUG("context already locked\n");
    1086           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
    1087           0 :                 return tevent_req_post(req, ev);
    1088             :         }
    1089             : 
    1090         110 :         switch (type) {
    1091           2 :             case NETLOGON_CREDS_CLI_LCK_SHARED:
    1092           2 :                     gtype = G_LOCK_READ;
    1093           2 :                     break;
    1094         108 :             case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
    1095         108 :                     gtype = G_LOCK_WRITE;
    1096         108 :                     break;
    1097           0 :             default:
    1098           0 :                     tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    1099           0 :                     return tevent_req_post(req, ev);
    1100             :         }
    1101             : 
    1102         110 :         state->lck = talloc(state, struct netlogon_creds_cli_lck);
    1103         110 :         if (tevent_req_nomem(state->lck, req)) {
    1104           0 :                 return tevent_req_post(req, ev);
    1105             :         }
    1106         110 :         state->lck->context = context;
    1107         110 :         state->type = type;
    1108             : 
    1109         110 :         subreq = g_lock_lock_send(state, ev,
    1110             :                                   context->db.g_ctx,
    1111             :                                   string_term_tdb_data(context->db.key_name),
    1112             :                                   gtype);
    1113         110 :         if (tevent_req_nomem(subreq, req)) {
    1114           0 :                 return tevent_req_post(req, ev);
    1115             :         }
    1116         110 :         tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
    1117             : 
    1118         110 :         return req;
    1119             : }
    1120             : 
    1121         110 : static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
    1122             : {
    1123         110 :         struct tevent_req *req = tevent_req_callback_data(
    1124             :                 subreq, struct tevent_req);
    1125         110 :         struct netlogon_creds_cli_lck_state *state = tevent_req_data(
    1126             :                 req, struct netlogon_creds_cli_lck_state);
    1127             :         NTSTATUS status;
    1128             : 
    1129         110 :         status = g_lock_lock_recv(subreq);
    1130         110 :         TALLOC_FREE(subreq);
    1131         110 :         if (tevent_req_nterror(req, status)) {
    1132           0 :                 return;
    1133             :         }
    1134             : 
    1135         110 :         state->lck->context->db.lock = state->type;
    1136         110 :         talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
    1137             : 
    1138         110 :         tevent_req_done(req);
    1139             : }
    1140             : 
    1141         110 : static int netlogon_creds_cli_lck_destructor(
    1142             :         struct netlogon_creds_cli_lck *lck)
    1143             : {
    1144         110 :         struct netlogon_creds_cli_context *ctx = lck->context;
    1145             :         NTSTATUS status;
    1146             : 
    1147         110 :         status = g_lock_unlock(ctx->db.g_ctx,
    1148             :                                string_term_tdb_data(ctx->db.key_name));
    1149         110 :         if (!NT_STATUS_IS_OK(status)) {
    1150           0 :                 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
    1151           0 :                 smb_panic("g_lock_unlock failed");
    1152             :         }
    1153         110 :         ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
    1154         110 :         return 0;
    1155             : }
    1156             : 
    1157         110 : NTSTATUS netlogon_creds_cli_lck_recv(
    1158             :         struct tevent_req *req, TALLOC_CTX *mem_ctx,
    1159             :         struct netlogon_creds_cli_lck **lck)
    1160             : {
    1161         110 :         struct netlogon_creds_cli_lck_state *state = tevent_req_data(
    1162             :                 req, struct netlogon_creds_cli_lck_state);
    1163             :         NTSTATUS status;
    1164             : 
    1165         110 :         if (tevent_req_is_nterror(req, &status)) {
    1166           0 :                 return status;
    1167             :         }
    1168         110 :         *lck = talloc_move(mem_ctx, &state->lck);
    1169         110 :         return NT_STATUS_OK;
    1170             : }
    1171             : 
    1172         110 : NTSTATUS netlogon_creds_cli_lck(
    1173             :         struct netlogon_creds_cli_context *context,
    1174             :         enum netlogon_creds_cli_lck_type type,
    1175             :         TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
    1176             : {
    1177         110 :         TALLOC_CTX *frame = talloc_stackframe();
    1178             :         struct tevent_context *ev;
    1179             :         struct tevent_req *req;
    1180         110 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1181             : 
    1182         110 :         ev = samba_tevent_context_init(frame);
    1183         110 :         if (ev == NULL) {
    1184           0 :                 goto fail;
    1185             :         }
    1186         110 :         req = netlogon_creds_cli_lck_send(frame, ev, context, type);
    1187         110 :         if (req == NULL) {
    1188           0 :                 goto fail;
    1189             :         }
    1190         110 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1191           0 :                 goto fail;
    1192             :         }
    1193         110 :         status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
    1194         110 :  fail:
    1195         110 :         TALLOC_FREE(frame);
    1196         110 :         return status;
    1197             : }
    1198             : 
    1199             : struct netlogon_creds_cli_auth_state {
    1200             :         struct tevent_context *ev;
    1201             :         struct netlogon_creds_cli_context *context;
    1202             :         struct dcerpc_binding_handle *binding_handle;
    1203             :         uint8_t num_nt_hashes;
    1204             :         uint8_t idx_nt_hashes;
    1205             :         const struct samr_Password * const *nt_hashes;
    1206             :         const struct samr_Password *used_nt_hash;
    1207             :         char *srv_name_slash;
    1208             :         uint32_t current_flags;
    1209             :         struct netr_Credential client_challenge;
    1210             :         struct netr_Credential server_challenge;
    1211             :         struct netlogon_creds_CredentialState *creds;
    1212             :         struct netr_Credential client_credential;
    1213             :         struct netr_Credential server_credential;
    1214             :         uint32_t rid;
    1215             :         bool try_auth3;
    1216             :         bool try_auth2;
    1217             :         bool require_auth2;
    1218             : };
    1219             : 
    1220             : static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
    1221             : 
    1222          36 : struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
    1223             :                                 struct tevent_context *ev,
    1224             :                                 struct netlogon_creds_cli_context *context,
    1225             :                                 struct dcerpc_binding_handle *b,
    1226             :                                 uint8_t num_nt_hashes,
    1227             :                                 const struct samr_Password * const *nt_hashes)
    1228             : {
    1229             :         struct tevent_req *req;
    1230             :         struct netlogon_creds_cli_auth_state *state;
    1231             :         NTSTATUS status;
    1232             : 
    1233          36 :         req = tevent_req_create(mem_ctx, &state,
    1234             :                                 struct netlogon_creds_cli_auth_state);
    1235          36 :         if (req == NULL) {
    1236           0 :                 return NULL;
    1237             :         }
    1238             : 
    1239          36 :         state->ev = ev;
    1240          36 :         state->context = context;
    1241          36 :         state->binding_handle = b;
    1242          36 :         if (num_nt_hashes < 1) {
    1243           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    1244           0 :                 return tevent_req_post(req, ev);
    1245             :         }
    1246          36 :         if (num_nt_hashes > 4) {
    1247           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    1248           0 :                 return tevent_req_post(req, ev);
    1249             :         }
    1250             : 
    1251          36 :         state->num_nt_hashes = num_nt_hashes;
    1252          36 :         state->idx_nt_hashes = 0;
    1253          36 :         state->nt_hashes = nt_hashes;
    1254             : 
    1255          36 :         if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
    1256           0 :                 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
    1257           0 :                 return tevent_req_post(req, ev);
    1258             :         }
    1259             : 
    1260          36 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    1261             :                                                 context->server.computer);
    1262          36 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    1263           0 :                 return tevent_req_post(req, ev);
    1264             :         }
    1265             : 
    1266          36 :         state->try_auth3 = true;
    1267          36 :         state->try_auth2 = true;
    1268             : 
    1269          36 :         if (context->client.required_flags != 0) {
    1270          36 :                 state->require_auth2 = true;
    1271             :         }
    1272             : 
    1273          36 :         state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
    1274          36 :         state->current_flags = context->client.proposed_flags;
    1275             : 
    1276          36 :         status = dbwrap_purge(state->context->db.ctx,
    1277          36 :                               state->context->db.key_data);
    1278          36 :         if (tevent_req_nterror(req, status)) {
    1279           0 :                 return tevent_req_post(req, ev);
    1280             :         }
    1281             : 
    1282          36 :         netlogon_creds_cli_auth_challenge_start(req);
    1283          36 :         if (!tevent_req_is_in_progress(req)) {
    1284           0 :                 return tevent_req_post(req, ev);
    1285             :         }
    1286             : 
    1287          36 :         return req;
    1288             : }
    1289             : 
    1290             : static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
    1291             : 
    1292          37 : static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
    1293             : {
    1294          24 :         struct netlogon_creds_cli_auth_state *state =
    1295          37 :                 tevent_req_data(req,
    1296             :                 struct netlogon_creds_cli_auth_state);
    1297             :         struct tevent_req *subreq;
    1298             : 
    1299          37 :         TALLOC_FREE(state->creds);
    1300             : 
    1301          37 :         netlogon_creds_random_challenge(&state->client_challenge);
    1302             : 
    1303          85 :         subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
    1304             :                                                 state->binding_handle,
    1305          37 :                                                 state->srv_name_slash,
    1306          37 :                                                 state->context->client.computer,
    1307             :                                                 &state->client_challenge,
    1308             :                                                 &state->server_challenge);
    1309          37 :         if (tevent_req_nomem(subreq, req)) {
    1310           0 :                 return;
    1311             :         }
    1312          37 :         tevent_req_set_callback(subreq,
    1313             :                                 netlogon_creds_cli_auth_challenge_done,
    1314             :                                 req);
    1315             : }
    1316             : 
    1317             : static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
    1318             : 
    1319          37 : static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
    1320             : {
    1321          24 :         struct tevent_req *req =
    1322          37 :                 tevent_req_callback_data(subreq,
    1323             :                 struct tevent_req);
    1324          24 :         struct netlogon_creds_cli_auth_state *state =
    1325          37 :                 tevent_req_data(req,
    1326             :                 struct netlogon_creds_cli_auth_state);
    1327             :         NTSTATUS status;
    1328             :         NTSTATUS result;
    1329             : 
    1330          37 :         status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
    1331          37 :         TALLOC_FREE(subreq);
    1332          37 :         if (tevent_req_nterror(req, status)) {
    1333           0 :                 return;
    1334             :         }
    1335          37 :         if (tevent_req_nterror(req, result)) {
    1336           0 :                 return;
    1337             :         }
    1338             : 
    1339          37 :         if (!state->try_auth3 && !state->try_auth2) {
    1340           0 :                 state->current_flags = 0;
    1341             :         }
    1342             : 
    1343             :         /* Calculate the session key and client credentials */
    1344             : 
    1345         122 :         state->creds = netlogon_creds_client_init(state,
    1346          37 :                                                   state->context->client.account,
    1347          37 :                                                   state->context->client.computer,
    1348          37 :                                                   state->context->client.type,
    1349          37 :                                                   &state->client_challenge,
    1350          37 :                                                   &state->server_challenge,
    1351             :                                                   state->used_nt_hash,
    1352             :                                                   &state->client_credential,
    1353             :                                                   state->current_flags);
    1354          37 :         if (tevent_req_nomem(state->creds, req)) {
    1355           0 :                 return;
    1356             :         }
    1357             : 
    1358          37 :         if (state->try_auth3) {
    1359         157 :                 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
    1360             :                                                 state->binding_handle,
    1361          37 :                                                 state->srv_name_slash,
    1362          37 :                                                 state->context->client.account,
    1363          37 :                                                 state->context->client.type,
    1364          37 :                                                 state->context->client.computer,
    1365             :                                                 &state->client_credential,
    1366             :                                                 &state->server_credential,
    1367          37 :                                                 &state->creds->negotiate_flags,
    1368             :                                                 &state->rid);
    1369          37 :                 if (tevent_req_nomem(subreq, req)) {
    1370           0 :                         return;
    1371             :                 }
    1372           0 :         } else if (state->try_auth2) {
    1373           0 :                 state->rid = 0;
    1374             : 
    1375           0 :                 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
    1376             :                                                 state->binding_handle,
    1377           0 :                                                 state->srv_name_slash,
    1378           0 :                                                 state->context->client.account,
    1379           0 :                                                 state->context->client.type,
    1380           0 :                                                 state->context->client.computer,
    1381             :                                                 &state->client_credential,
    1382             :                                                 &state->server_credential,
    1383           0 :                                                 &state->creds->negotiate_flags);
    1384           0 :                 if (tevent_req_nomem(subreq, req)) {
    1385           0 :                         return;
    1386             :                 }
    1387             :         } else {
    1388           0 :                 state->rid = 0;
    1389             : 
    1390           0 :                 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
    1391             :                                                 state->binding_handle,
    1392           0 :                                                 state->srv_name_slash,
    1393           0 :                                                 state->context->client.account,
    1394           0 :                                                 state->context->client.type,
    1395           0 :                                                 state->context->client.computer,
    1396             :                                                 &state->client_credential,
    1397             :                                                 &state->server_credential);
    1398           0 :                 if (tevent_req_nomem(subreq, req)) {
    1399           0 :                         return;
    1400             :                 }
    1401             :         }
    1402          37 :         tevent_req_set_callback(subreq,
    1403             :                                 netlogon_creds_cli_auth_srvauth_done,
    1404             :                                 req);
    1405             : }
    1406             : 
    1407          37 : static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
    1408             : {
    1409          24 :         struct tevent_req *req =
    1410          37 :                 tevent_req_callback_data(subreq,
    1411             :                 struct tevent_req);
    1412          24 :         struct netlogon_creds_cli_auth_state *state =
    1413          37 :                 tevent_req_data(req,
    1414             :                 struct netlogon_creds_cli_auth_state);
    1415             :         NTSTATUS status;
    1416             :         NTSTATUS result;
    1417             :         bool ok;
    1418             :         enum ndr_err_code ndr_err;
    1419             :         DATA_BLOB blob;
    1420             :         TDB_DATA data;
    1421             :         bool downgraded;
    1422             : 
    1423          37 :         if (state->try_auth3) {
    1424          37 :                 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
    1425             :                                                               &result);
    1426          37 :                 TALLOC_FREE(subreq);
    1427          37 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
    1428           0 :                         state->try_auth3 = false;
    1429           0 :                         netlogon_creds_cli_auth_challenge_start(req);
    1430           0 :                         return;
    1431             :                 }
    1432          37 :                 if (tevent_req_nterror(req, status)) {
    1433           0 :                         return;
    1434             :                 }
    1435           0 :         } else if (state->try_auth2) {
    1436           0 :                 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
    1437             :                                                               &result);
    1438           0 :                 TALLOC_FREE(subreq);
    1439           0 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
    1440           0 :                         state->try_auth2 = false;
    1441           0 :                         if (state->require_auth2) {
    1442           0 :                                 status = NT_STATUS_DOWNGRADE_DETECTED;
    1443           0 :                                 tevent_req_nterror(req, status);
    1444           0 :                                 return;
    1445             :                         }
    1446           0 :                         netlogon_creds_cli_auth_challenge_start(req);
    1447           0 :                         return;
    1448             :                 }
    1449           0 :                 if (tevent_req_nterror(req, status)) {
    1450           0 :                         return;
    1451             :                 }
    1452             :         } else {
    1453           0 :                 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
    1454             :                                                              &result);
    1455           0 :                 TALLOC_FREE(subreq);
    1456           0 :                 if (tevent_req_nterror(req, status)) {
    1457           0 :                         return;
    1458             :                 }
    1459             :         }
    1460             : 
    1461          39 :         if (!NT_STATUS_IS_OK(result) &&
    1462           2 :             !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
    1463             :         {
    1464           0 :                 tevent_req_nterror(req, result);
    1465           0 :                 return;
    1466             :         }
    1467             : 
    1468          85 :         downgraded = netlogon_creds_cli_downgraded(
    1469          37 :                         state->creds->negotiate_flags,
    1470          37 :                         state->context->client.proposed_flags,
    1471          37 :                         state->context->client.required_flags);
    1472          37 :         if (downgraded) {
    1473           0 :                 if (NT_STATUS_IS_OK(result)) {
    1474           0 :                         tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
    1475           0 :                         return;
    1476             :                 }
    1477           0 :                 tevent_req_nterror(req, result);
    1478           0 :                 return;
    1479             :         }
    1480             : 
    1481          37 :         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
    1482           2 :                 uint32_t tmp_flags = state->context->client.proposed_flags;
    1483           3 :                 if ((state->current_flags == tmp_flags) &&
    1484           1 :                     (state->creds->negotiate_flags != tmp_flags))
    1485             :                 {
    1486             :                         /*
    1487             :                          * lets retry with the negotiated flags
    1488             :                          */
    1489           1 :                         state->current_flags = state->creds->negotiate_flags;
    1490           1 :                         netlogon_creds_cli_auth_challenge_start(req);
    1491           1 :                         return;
    1492             :                 }
    1493             : 
    1494           1 :                 state->idx_nt_hashes += 1;
    1495           1 :                 if (state->idx_nt_hashes >= state->num_nt_hashes) {
    1496             :                         /*
    1497             :                          * we already retried, giving up...
    1498             :                          */
    1499           1 :                         tevent_req_nterror(req, result);
    1500           1 :                         return;
    1501             :                 }
    1502             : 
    1503             :                 /*
    1504             :                  * lets retry with the old nt hash.
    1505             :                  */
    1506           0 :                 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
    1507           0 :                 state->current_flags = state->context->client.proposed_flags;
    1508           0 :                 netlogon_creds_cli_auth_challenge_start(req);
    1509           0 :                 return;
    1510             :         }
    1511             : 
    1512          35 :         ok = netlogon_creds_client_check(state->creds,
    1513          35 :                                          &state->server_credential);
    1514          35 :         if (!ok) {
    1515           0 :                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
    1516           0 :                 return;
    1517             :         }
    1518             : 
    1519          35 :         ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
    1520             :                 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
    1521          35 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1522           0 :                 status = ndr_map_error2ntstatus(ndr_err);
    1523           0 :                 tevent_req_nterror(req, status);
    1524           0 :                 return;
    1525             :         }
    1526             : 
    1527          35 :         data.dptr = blob.data;
    1528          35 :         data.dsize = blob.length;
    1529             : 
    1530          35 :         status = dbwrap_store(state->context->db.ctx,
    1531          35 :                               state->context->db.key_data,
    1532             :                               data, TDB_REPLACE);
    1533          35 :         if (tevent_req_nterror(req, status)) {
    1534           0 :                 return;
    1535             :         }
    1536             : 
    1537          35 :         tevent_req_done(req);
    1538             : }
    1539             : 
    1540          36 : NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
    1541             :                                       uint8_t *idx_nt_hashes)
    1542             : {
    1543          23 :         struct netlogon_creds_cli_auth_state *state =
    1544          36 :                 tevent_req_data(req,
    1545             :                 struct netlogon_creds_cli_auth_state);
    1546             :         NTSTATUS status;
    1547             : 
    1548          36 :         *idx_nt_hashes = 0;
    1549             : 
    1550          36 :         if (tevent_req_is_nterror(req, &status)) {
    1551           1 :                 tevent_req_received(req);
    1552           1 :                 return status;
    1553             :         }
    1554             : 
    1555          35 :         *idx_nt_hashes = state->idx_nt_hashes;
    1556          35 :         tevent_req_received(req);
    1557          35 :         return NT_STATUS_OK;
    1558             : }
    1559             : 
    1560          36 : NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
    1561             :                                  struct dcerpc_binding_handle *b,
    1562             :                                  uint8_t num_nt_hashes,
    1563             :                                  const struct samr_Password * const *nt_hashes,
    1564             :                                  uint8_t *idx_nt_hashes)
    1565             : {
    1566          36 :         TALLOC_CTX *frame = talloc_stackframe();
    1567             :         struct tevent_context *ev;
    1568             :         struct tevent_req *req;
    1569          36 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1570             : 
    1571          36 :         *idx_nt_hashes = 0;
    1572             : 
    1573          36 :         ev = samba_tevent_context_init(frame);
    1574          36 :         if (ev == NULL) {
    1575           0 :                 goto fail;
    1576             :         }
    1577          36 :         req = netlogon_creds_cli_auth_send(frame, ev, context, b,
    1578             :                                            num_nt_hashes, nt_hashes);
    1579          36 :         if (req == NULL) {
    1580           0 :                 goto fail;
    1581             :         }
    1582          36 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1583           0 :                 goto fail;
    1584             :         }
    1585          36 :         status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
    1586          36 :  fail:
    1587          36 :         TALLOC_FREE(frame);
    1588          36 :         return status;
    1589             : }
    1590             : 
    1591             : struct netlogon_creds_cli_check_state {
    1592             :         struct tevent_context *ev;
    1593             :         struct netlogon_creds_cli_context *context;
    1594             :         struct dcerpc_binding_handle *binding_handle;
    1595             : 
    1596             :         char *srv_name_slash;
    1597             : 
    1598             :         union netr_Capabilities caps;
    1599             : 
    1600             :         struct netlogon_creds_CredentialState *creds;
    1601             :         struct netr_Authenticator req_auth;
    1602             :         struct netr_Authenticator rep_auth;
    1603             : };
    1604             : 
    1605             : static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
    1606             :                                              NTSTATUS status);
    1607             : static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
    1608             : 
    1609          45 : struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
    1610             :                                 struct tevent_context *ev,
    1611             :                                 struct netlogon_creds_cli_context *context,
    1612             :                                 struct dcerpc_binding_handle *b)
    1613             : {
    1614             :         struct tevent_req *req;
    1615             :         struct netlogon_creds_cli_check_state *state;
    1616             :         struct tevent_req *subreq;
    1617             :         enum dcerpc_AuthType auth_type;
    1618             :         enum dcerpc_AuthLevel auth_level;
    1619             :         NTSTATUS status;
    1620             : 
    1621          45 :         req = tevent_req_create(mem_ctx, &state,
    1622             :                                 struct netlogon_creds_cli_check_state);
    1623          45 :         if (req == NULL) {
    1624           0 :                 return NULL;
    1625             :         }
    1626             : 
    1627          45 :         state->ev = ev;
    1628          45 :         state->context = context;
    1629          45 :         state->binding_handle = b;
    1630             : 
    1631          45 :         if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
    1632           0 :                 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
    1633           0 :                 return tevent_req_post(req, ev);
    1634             :         }
    1635             : 
    1636          45 :         status = netlogon_creds_cli_get_internal(context, state,
    1637          45 :                                                  &state->creds);
    1638          45 :         if (tevent_req_nterror(req, status)) {
    1639           0 :                 return tevent_req_post(req, ev);
    1640             :         }
    1641             : 
    1642          45 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    1643             :                                                 context->server.computer);
    1644          45 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    1645           0 :                 return tevent_req_post(req, ev);
    1646             :         }
    1647             : 
    1648          45 :         dcerpc_binding_handle_auth_info(state->binding_handle,
    1649             :                                         &auth_type, &auth_level);
    1650             : 
    1651          45 :         if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
    1652           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    1653           0 :                 return tevent_req_post(req, ev);
    1654             :         }
    1655             : 
    1656          45 :         switch (auth_level) {
    1657          45 :         case DCERPC_AUTH_LEVEL_INTEGRITY:
    1658             :         case DCERPC_AUTH_LEVEL_PRIVACY:
    1659          45 :                 break;
    1660           0 :         default:
    1661           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    1662           0 :                 return tevent_req_post(req, ev);
    1663             :         }
    1664             : 
    1665             :         /*
    1666             :          * we defer all callbacks in order to cleanup
    1667             :          * the database record.
    1668             :          */
    1669          45 :         tevent_req_defer_callback(req, state->ev);
    1670             : 
    1671          45 :         status = netlogon_creds_client_authenticator(state->creds,
    1672          45 :                                                      &state->req_auth);
    1673          45 :         if (tevent_req_nterror(req, status)) {
    1674           0 :                 return tevent_req_post(req, ev);
    1675             :         }
    1676          45 :         ZERO_STRUCT(state->rep_auth);
    1677             : 
    1678         165 :         subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
    1679          45 :                                                 state->binding_handle,
    1680          45 :                                                 state->srv_name_slash,
    1681          45 :                                                 state->context->client.computer,
    1682          45 :                                                 &state->req_auth,
    1683          45 :                                                 &state->rep_auth,
    1684             :                                                 1,
    1685          45 :                                                 &state->caps);
    1686          45 :         if (tevent_req_nomem(subreq, req)) {
    1687           0 :                 return tevent_req_post(req, ev);
    1688             :         }
    1689             : 
    1690          45 :         tevent_req_set_callback(subreq,
    1691             :                                 netlogon_creds_cli_check_caps,
    1692             :                                 req);
    1693             : 
    1694          45 :         return req;
    1695             : }
    1696             : 
    1697           0 : static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
    1698             :                                              NTSTATUS status)
    1699             : {
    1700           0 :         struct netlogon_creds_cli_check_state *state =
    1701           0 :                 tevent_req_data(req,
    1702             :                 struct netlogon_creds_cli_check_state);
    1703             : 
    1704           0 :         if (state->creds == NULL) {
    1705           0 :                 return;
    1706             :         }
    1707             : 
    1708           0 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
    1709           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
    1710           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
    1711           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
    1712           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
    1713           0 :                 TALLOC_FREE(state->creds);
    1714           0 :                 return;
    1715             :         }
    1716             : 
    1717           0 :         netlogon_creds_cli_delete_lck(state->context);
    1718           0 :         TALLOC_FREE(state->creds);
    1719             : }
    1720             : 
    1721          45 : static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
    1722             : {
    1723          30 :         struct tevent_req *req =
    1724          45 :                 tevent_req_callback_data(subreq,
    1725             :                 struct tevent_req);
    1726          30 :         struct netlogon_creds_cli_check_state *state =
    1727          45 :                 tevent_req_data(req,
    1728             :                 struct netlogon_creds_cli_check_state);
    1729             :         NTSTATUS status;
    1730             :         NTSTATUS result;
    1731             :         bool ok;
    1732             : 
    1733          45 :         status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
    1734             :                                                        &result);
    1735          45 :         TALLOC_FREE(subreq);
    1736          45 :         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
    1737             :                 /*
    1738             :                  * Note that the negotiated flags are already checked
    1739             :                  * for our required flags after the ServerAuthenticate3/2 call.
    1740             :                  */
    1741           0 :                 uint32_t negotiated = state->creds->negotiate_flags;
    1742             : 
    1743           0 :                 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
    1744             :                         /*
    1745             :                          * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
    1746             :                          * already, we expect this to work!
    1747             :                          */
    1748           0 :                         status = NT_STATUS_DOWNGRADE_DETECTED;
    1749           0 :                         tevent_req_nterror(req, status);
    1750           0 :                         netlogon_creds_cli_check_cleanup(req, status);
    1751           0 :                         return;
    1752             :                 }
    1753             : 
    1754           0 :                 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
    1755             :                         /*
    1756             :                          * If we have negotiated NETLOGON_NEG_STRONG_KEYS
    1757             :                          * we expect this to work at least as far as the
    1758             :                          * NOT_SUPPORTED error handled below!
    1759             :                          *
    1760             :                          * NT 4.0 and Old Samba servers are not
    1761             :                          * allowed without "require strong key = no"
    1762             :                          */
    1763           0 :                         status = NT_STATUS_DOWNGRADE_DETECTED;
    1764           0 :                         tevent_req_nterror(req, status);
    1765           0 :                         netlogon_creds_cli_check_cleanup(req, status);
    1766           0 :                         return;
    1767             :                 }
    1768             : 
    1769             :                 /*
    1770             :                  * If we not require NETLOGON_NEG_SUPPORTS_AES or
    1771             :                  * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
    1772             :                  * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
    1773             :                  *
    1774             :                  * This is needed against NT 4.0 and old Samba servers.
    1775             :                  *
    1776             :                  * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
    1777             :                  * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
    1778             :                  * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
    1779             :                  * with the next request as the sequence number processing
    1780             :                  * gets out of sync.
    1781             :                  */
    1782           0 :                 netlogon_creds_cli_check_cleanup(req, status);
    1783           0 :                 tevent_req_done(req);
    1784           0 :                 return;
    1785             :         }
    1786          45 :         if (tevent_req_nterror(req, status)) {
    1787           0 :                 netlogon_creds_cli_check_cleanup(req, status);
    1788           0 :                 return;
    1789             :         }
    1790             : 
    1791          45 :         if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
    1792             :                 /*
    1793             :                  * Note that the negotiated flags are already checked
    1794             :                  * for our required flags after the ServerAuthenticate3/2 call.
    1795             :                  */
    1796           0 :                 uint32_t negotiated = state->creds->negotiate_flags;
    1797             : 
    1798           0 :                 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
    1799             :                         /*
    1800             :                          * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
    1801             :                          * already, we expect this to work!
    1802             :                          */
    1803           0 :                         status = NT_STATUS_DOWNGRADE_DETECTED;
    1804           0 :                         tevent_req_nterror(req, status);
    1805           0 :                         netlogon_creds_cli_check_cleanup(req, status);
    1806           0 :                         return;
    1807             :                 }
    1808             : 
    1809             :                 /*
    1810             :                  * This is ok, the server does not support
    1811             :                  * NETLOGON_NEG_SUPPORTS_AES.
    1812             :                  *
    1813             :                  * netr_LogonGetCapabilities() was
    1814             :                  * netr_LogonDummyRoutine1() before
    1815             :                  * NETLOGON_NEG_SUPPORTS_AES was invented.
    1816             :                  */
    1817           0 :                 netlogon_creds_cli_check_cleanup(req, result);
    1818           0 :                 tevent_req_done(req);
    1819           0 :                 return;
    1820             :         }
    1821             : 
    1822          45 :         ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
    1823          45 :         if (!ok) {
    1824           0 :                 status = NT_STATUS_ACCESS_DENIED;
    1825           0 :                 tevent_req_nterror(req, status);
    1826           0 :                 netlogon_creds_cli_check_cleanup(req, status);
    1827           0 :                 return;
    1828             :         }
    1829             : 
    1830          45 :         if (tevent_req_nterror(req, result)) {
    1831           0 :                 netlogon_creds_cli_check_cleanup(req, result);
    1832           0 :                 return;
    1833             :         }
    1834             : 
    1835          45 :         if (state->caps.server_capabilities != state->creds->negotiate_flags) {
    1836           0 :                 status = NT_STATUS_DOWNGRADE_DETECTED;
    1837           0 :                 tevent_req_nterror(req, status);
    1838           0 :                 netlogon_creds_cli_check_cleanup(req, status);
    1839           0 :                 return;
    1840             :         }
    1841             : 
    1842             :         /*
    1843             :          * This is the key check that makes this check secure.  If we
    1844             :          * get OK here (rather than NOT_SUPPORTED), then the server
    1845             :          * did support AES. If the server only proposed STRONG_KEYS
    1846             :          * and not AES, then it should have failed with
    1847             :          * NOT_IMPLEMENTED. We always send AES as a client, so the
    1848             :          * server should always have returned it.
    1849             :          */
    1850          45 :         if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
    1851           0 :                 status = NT_STATUS_DOWNGRADE_DETECTED;
    1852           0 :                 tevent_req_nterror(req, status);
    1853           0 :                 netlogon_creds_cli_check_cleanup(req, status);
    1854           0 :                 return;
    1855             :         }
    1856             : 
    1857          45 :         status = netlogon_creds_cli_store_internal(state->context,
    1858             :                                                    state->creds);
    1859          45 :         if (tevent_req_nterror(req, status)) {
    1860           0 :                 return;
    1861             :         }
    1862             : 
    1863          45 :         tevent_req_done(req);
    1864             : }
    1865             : 
    1866          45 : NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
    1867             :                                        union netr_Capabilities *capabilities)
    1868             : {
    1869          45 :         struct netlogon_creds_cli_check_state *state = tevent_req_data(
    1870             :                 req, struct netlogon_creds_cli_check_state);
    1871             :         NTSTATUS status;
    1872             : 
    1873          45 :         if (tevent_req_is_nterror(req, &status)) {
    1874           0 :                 netlogon_creds_cli_check_cleanup(req, status);
    1875           0 :                 tevent_req_received(req);
    1876           0 :                 return status;
    1877             :         }
    1878             : 
    1879          45 :         if (capabilities != NULL) {
    1880           0 :                 *capabilities = state->caps;
    1881             :         }
    1882             : 
    1883          45 :         tevent_req_received(req);
    1884          45 :         return NT_STATUS_OK;
    1885             : }
    1886             : 
    1887          45 : NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
    1888             :                                   struct dcerpc_binding_handle *b,
    1889             :                                   union netr_Capabilities *capabilities)
    1890             : {
    1891          45 :         TALLOC_CTX *frame = talloc_stackframe();
    1892             :         struct tevent_context *ev;
    1893             :         struct tevent_req *req;
    1894          45 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1895             : 
    1896          45 :         ev = samba_tevent_context_init(frame);
    1897          45 :         if (ev == NULL) {
    1898           0 :                 goto fail;
    1899             :         }
    1900          45 :         req = netlogon_creds_cli_check_send(frame, ev, context, b);
    1901          45 :         if (req == NULL) {
    1902           0 :                 goto fail;
    1903             :         }
    1904          45 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1905           0 :                 goto fail;
    1906             :         }
    1907          45 :         status = netlogon_creds_cli_check_recv(req, capabilities);
    1908          45 :  fail:
    1909          45 :         TALLOC_FREE(frame);
    1910          45 :         return status;
    1911             : }
    1912             : 
    1913             : struct netlogon_creds_cli_ServerPasswordSet_state {
    1914             :         struct tevent_context *ev;
    1915             :         struct netlogon_creds_cli_context *context;
    1916             :         struct dcerpc_binding_handle *binding_handle;
    1917             :         uint32_t old_timeout;
    1918             : 
    1919             :         char *srv_name_slash;
    1920             :         enum dcerpc_AuthType auth_type;
    1921             :         enum dcerpc_AuthLevel auth_level;
    1922             : 
    1923             :         struct samr_CryptPassword samr_crypt_password;
    1924             :         struct netr_CryptPassword netr_crypt_password;
    1925             :         struct samr_Password samr_password;
    1926             : 
    1927             :         struct netlogon_creds_CredentialState *creds;
    1928             :         struct netlogon_creds_CredentialState tmp_creds;
    1929             :         struct netr_Authenticator req_auth;
    1930             :         struct netr_Authenticator rep_auth;
    1931             : };
    1932             : 
    1933             : static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
    1934             :                                                      NTSTATUS status);
    1935             : static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
    1936             : 
    1937           0 : struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
    1938             :                                 struct tevent_context *ev,
    1939             :                                 struct netlogon_creds_cli_context *context,
    1940             :                                 struct dcerpc_binding_handle *b,
    1941             :                                 const DATA_BLOB *new_password,
    1942             :                                 const uint32_t *new_version)
    1943             : {
    1944             :         struct tevent_req *req;
    1945             :         struct netlogon_creds_cli_ServerPasswordSet_state *state;
    1946             :         struct tevent_req *subreq;
    1947             :         bool ok;
    1948             : 
    1949           0 :         req = tevent_req_create(mem_ctx, &state,
    1950             :                                 struct netlogon_creds_cli_ServerPasswordSet_state);
    1951           0 :         if (req == NULL) {
    1952           0 :                 return NULL;
    1953             :         }
    1954             : 
    1955           0 :         state->ev = ev;
    1956           0 :         state->context = context;
    1957           0 :         state->binding_handle = b;
    1958             : 
    1959           0 :         if (new_password->length < 14) {
    1960           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    1961           0 :                 return tevent_req_post(req, ev);
    1962             :         }
    1963             : 
    1964             :         /*
    1965             :          * netr_ServerPasswordSet
    1966             :          */
    1967           0 :         mdfour(state->samr_password.hash, new_password->data, new_password->length);
    1968             : 
    1969             :         /*
    1970             :          * netr_ServerPasswordSet2
    1971             :          */
    1972           0 :         ok = set_pw_in_buffer(state->samr_crypt_password.data,
    1973             :                               new_password);
    1974           0 :         if (!ok) {
    1975           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    1976           0 :                 return tevent_req_post(req, ev);
    1977             :         }
    1978             : 
    1979           0 :         if (new_version != NULL) {
    1980             :                 struct NL_PASSWORD_VERSION version;
    1981           0 :                 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
    1982           0 :                 uint32_t ofs = 512 - len;
    1983             :                 uint8_t *p;
    1984             : 
    1985           0 :                 if (len > 500) {
    1986           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    1987           0 :                         return tevent_req_post(req, ev);
    1988             :                 }
    1989           0 :                 ofs -= 12;
    1990             : 
    1991           0 :                 version.ReservedField = 0;
    1992           0 :                 version.PasswordVersionNumber = *new_version;
    1993           0 :                 version.PasswordVersionPresent =
    1994             :                         NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
    1995             : 
    1996           0 :                 p = state->samr_crypt_password.data + ofs;
    1997           0 :                 SIVAL(p, 0, version.ReservedField);
    1998           0 :                 SIVAL(p, 4, version.PasswordVersionNumber);
    1999           0 :                 SIVAL(p, 8, version.PasswordVersionPresent);
    2000             :         }
    2001             : 
    2002           0 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    2003             :                                                 context->server.computer);
    2004           0 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    2005           0 :                 return tevent_req_post(req, ev);
    2006             :         }
    2007             : 
    2008           0 :         dcerpc_binding_handle_auth_info(state->binding_handle,
    2009           0 :                                         &state->auth_type,
    2010           0 :                                         &state->auth_level);
    2011             : 
    2012           0 :         subreq = netlogon_creds_cli_lock_send(state, state->ev,
    2013           0 :                                               state->context);
    2014           0 :         if (tevent_req_nomem(subreq, req)) {
    2015           0 :                 return tevent_req_post(req, ev);
    2016             :         }
    2017             : 
    2018           0 :         tevent_req_set_callback(subreq,
    2019             :                                 netlogon_creds_cli_ServerPasswordSet_locked,
    2020             :                                 req);
    2021             : 
    2022           0 :         return req;
    2023             : }
    2024             : 
    2025           0 : static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
    2026             :                                                          NTSTATUS status)
    2027             : {
    2028           0 :         struct netlogon_creds_cli_ServerPasswordSet_state *state =
    2029           0 :                 tevent_req_data(req,
    2030             :                 struct netlogon_creds_cli_ServerPasswordSet_state);
    2031             : 
    2032           0 :         if (state->creds == NULL) {
    2033           0 :                 return;
    2034             :         }
    2035             : 
    2036           0 :         dcerpc_binding_handle_set_timeout(state->binding_handle,
    2037             :                                           state->old_timeout);
    2038             : 
    2039           0 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
    2040           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
    2041           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
    2042           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
    2043           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
    2044           0 :                 TALLOC_FREE(state->creds);
    2045           0 :                 return;
    2046             :         }
    2047             : 
    2048           0 :         netlogon_creds_cli_delete(state->context, state->creds);
    2049           0 :         TALLOC_FREE(state->creds);
    2050             : }
    2051             : 
    2052             : static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
    2053             : 
    2054           0 : static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
    2055             : {
    2056           0 :         struct tevent_req *req =
    2057           0 :                 tevent_req_callback_data(subreq,
    2058             :                 struct tevent_req);
    2059           0 :         struct netlogon_creds_cli_ServerPasswordSet_state *state =
    2060           0 :                 tevent_req_data(req,
    2061             :                 struct netlogon_creds_cli_ServerPasswordSet_state);
    2062             :         NTSTATUS status;
    2063             : 
    2064           0 :         status = netlogon_creds_cli_lock_recv(subreq, state,
    2065             :                                               &state->creds);
    2066           0 :         TALLOC_FREE(subreq);
    2067           0 :         if (tevent_req_nterror(req, status)) {
    2068           0 :                 return;
    2069             :         }
    2070             : 
    2071           0 :         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
    2072           0 :                 switch (state->auth_level) {
    2073           0 :                 case DCERPC_AUTH_LEVEL_INTEGRITY:
    2074             :                 case DCERPC_AUTH_LEVEL_PRIVACY:
    2075           0 :                         break;
    2076           0 :                 default:
    2077           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    2078           0 :                         return;
    2079             :                 }
    2080             :         } else {
    2081           0 :                 uint32_t tmp = state->creds->negotiate_flags;
    2082             : 
    2083           0 :                 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
    2084             :                         /*
    2085             :                          * if DCERPC_AUTH_TYPE_SCHANNEL is supported
    2086             :                          * it should be used, which means
    2087             :                          * we had a chance to verify no downgrade
    2088             :                          * happened.
    2089             :                          *
    2090             :                          * This relies on netlogon_creds_cli_check*
    2091             :                          * being called before, as first request after
    2092             :                          * the DCERPC bind.
    2093             :                          */
    2094           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    2095           0 :                         return;
    2096             :                 }
    2097             :         }
    2098             : 
    2099           0 :         state->old_timeout = dcerpc_binding_handle_set_timeout(
    2100             :                                 state->binding_handle, 600000);
    2101             : 
    2102             :         /*
    2103             :          * we defer all callbacks in order to cleanup
    2104             :          * the database record.
    2105             :          */
    2106           0 :         tevent_req_defer_callback(req, state->ev);
    2107             : 
    2108           0 :         state->tmp_creds = *state->creds;
    2109           0 :         status = netlogon_creds_client_authenticator(&state->tmp_creds,
    2110             :                                                      &state->req_auth);
    2111           0 :         if (tevent_req_nterror(req, status)) {
    2112           0 :                 return;
    2113             :         }
    2114           0 :         ZERO_STRUCT(state->rep_auth);
    2115             : 
    2116           0 :         if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
    2117             : 
    2118           0 :                 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
    2119           0 :                         status = netlogon_creds_aes_encrypt(&state->tmp_creds,
    2120           0 :                                                             state->samr_crypt_password.data,
    2121             :                                                             516);
    2122           0 :                         if (tevent_req_nterror(req, status)) {
    2123           0 :                                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
    2124           0 :                                 return;
    2125             :                         }
    2126             :                 } else {
    2127           0 :                         status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
    2128           0 :                                                               state->samr_crypt_password.data,
    2129             :                                                               516);
    2130           0 :                         if (tevent_req_nterror(req, status)) {
    2131           0 :                                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
    2132           0 :                                 return;
    2133             :                         }
    2134             :                 }
    2135             : 
    2136           0 :                 memcpy(state->netr_crypt_password.data,
    2137           0 :                        state->samr_crypt_password.data, 512);
    2138           0 :                 state->netr_crypt_password.length =
    2139           0 :                         IVAL(state->samr_crypt_password.data, 512);
    2140             : 
    2141           0 :                 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
    2142             :                                         state->binding_handle,
    2143           0 :                                         state->srv_name_slash,
    2144             :                                         state->tmp_creds.account_name,
    2145             :                                         state->tmp_creds.secure_channel_type,
    2146             :                                         state->tmp_creds.computer_name,
    2147             :                                         &state->req_auth,
    2148             :                                         &state->rep_auth,
    2149             :                                         &state->netr_crypt_password);
    2150           0 :                 if (tevent_req_nomem(subreq, req)) {
    2151           0 :                         status = NT_STATUS_NO_MEMORY;
    2152           0 :                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
    2153           0 :                         return;
    2154             :                 }
    2155             :         } else {
    2156           0 :                 status = netlogon_creds_des_encrypt(&state->tmp_creds,
    2157             :                                                     &state->samr_password);
    2158           0 :                 if (tevent_req_nterror(req, status)) {
    2159           0 :                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
    2160           0 :                         return;
    2161             :                 }
    2162             : 
    2163           0 :                 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
    2164             :                                         state->binding_handle,
    2165           0 :                                         state->srv_name_slash,
    2166             :                                         state->tmp_creds.account_name,
    2167             :                                         state->tmp_creds.secure_channel_type,
    2168             :                                         state->tmp_creds.computer_name,
    2169             :                                         &state->req_auth,
    2170             :                                         &state->rep_auth,
    2171             :                                         &state->samr_password);
    2172           0 :                 if (tevent_req_nomem(subreq, req)) {
    2173           0 :                         status = NT_STATUS_NO_MEMORY;
    2174           0 :                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
    2175           0 :                         return;
    2176             :                 }
    2177             :         }
    2178             : 
    2179           0 :         tevent_req_set_callback(subreq,
    2180             :                                 netlogon_creds_cli_ServerPasswordSet_done,
    2181             :                                 req);
    2182             : }
    2183             : 
    2184           0 : static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
    2185             : {
    2186           0 :         struct tevent_req *req =
    2187           0 :                 tevent_req_callback_data(subreq,
    2188             :                 struct tevent_req);
    2189           0 :         struct netlogon_creds_cli_ServerPasswordSet_state *state =
    2190           0 :                 tevent_req_data(req,
    2191             :                 struct netlogon_creds_cli_ServerPasswordSet_state);
    2192             :         NTSTATUS status;
    2193             :         NTSTATUS result;
    2194             :         bool ok;
    2195             : 
    2196           0 :         if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
    2197           0 :                 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
    2198             :                                                              &result);
    2199           0 :                 TALLOC_FREE(subreq);
    2200           0 :                 if (tevent_req_nterror(req, status)) {
    2201           0 :                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
    2202           0 :                         return;
    2203             :                 }
    2204             :         } else {
    2205           0 :                 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
    2206             :                                                             &result);
    2207           0 :                 TALLOC_FREE(subreq);
    2208           0 :                 if (tevent_req_nterror(req, status)) {
    2209           0 :                         netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
    2210           0 :                         return;
    2211             :                 }
    2212             :         }
    2213             : 
    2214           0 :         ok = netlogon_creds_client_check(&state->tmp_creds,
    2215           0 :                                          &state->rep_auth.cred);
    2216           0 :         if (!ok) {
    2217           0 :                 status = NT_STATUS_ACCESS_DENIED;
    2218           0 :                 tevent_req_nterror(req, status);
    2219           0 :                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
    2220           0 :                 return;
    2221             :         }
    2222             : 
    2223           0 :         if (tevent_req_nterror(req, result)) {
    2224           0 :                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
    2225           0 :                 return;
    2226             :         }
    2227             : 
    2228           0 :         dcerpc_binding_handle_set_timeout(state->binding_handle,
    2229             :                                           state->old_timeout);
    2230             : 
    2231           0 :         *state->creds = state->tmp_creds;
    2232           0 :         status = netlogon_creds_cli_store(state->context,
    2233             :                                           state->creds);
    2234           0 :         TALLOC_FREE(state->creds);
    2235           0 :         if (tevent_req_nterror(req, status)) {
    2236           0 :                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
    2237           0 :                 return;
    2238             :         }
    2239             : 
    2240           0 :         tevent_req_done(req);
    2241             : }
    2242             : 
    2243           0 : NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
    2244             : {
    2245             :         NTSTATUS status;
    2246             : 
    2247           0 :         if (tevent_req_is_nterror(req, &status)) {
    2248           0 :                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
    2249           0 :                 tevent_req_received(req);
    2250           0 :                 return status;
    2251             :         }
    2252             : 
    2253           0 :         tevent_req_received(req);
    2254           0 :         return NT_STATUS_OK;
    2255             : }
    2256             : 
    2257           0 : NTSTATUS netlogon_creds_cli_ServerPasswordSet(
    2258             :                                 struct netlogon_creds_cli_context *context,
    2259             :                                 struct dcerpc_binding_handle *b,
    2260             :                                 const DATA_BLOB *new_password,
    2261             :                                 const uint32_t *new_version)
    2262             : {
    2263           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2264             :         struct tevent_context *ev;
    2265             :         struct tevent_req *req;
    2266           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    2267             : 
    2268           0 :         ev = samba_tevent_context_init(frame);
    2269           0 :         if (ev == NULL) {
    2270           0 :                 goto fail;
    2271             :         }
    2272           0 :         req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
    2273             :                                                         new_password,
    2274             :                                                         new_version);
    2275           0 :         if (req == NULL) {
    2276           0 :                 goto fail;
    2277             :         }
    2278           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    2279           0 :                 goto fail;
    2280             :         }
    2281           0 :         status = netlogon_creds_cli_ServerPasswordSet_recv(req);
    2282           0 :  fail:
    2283           0 :         TALLOC_FREE(frame);
    2284           0 :         return status;
    2285             : }
    2286             : 
    2287             : struct netlogon_creds_cli_LogonSamLogon_state {
    2288             :         struct tevent_context *ev;
    2289             :         struct netlogon_creds_cli_context *context;
    2290             :         struct dcerpc_binding_handle *binding_handle;
    2291             : 
    2292             :         char *srv_name_slash;
    2293             : 
    2294             :         enum netr_LogonInfoClass logon_level;
    2295             :         const union netr_LogonLevel *const_logon;
    2296             :         union netr_LogonLevel *logon;
    2297             :         uint32_t flags;
    2298             : 
    2299             :         uint16_t validation_level;
    2300             :         union netr_Validation *validation;
    2301             :         uint8_t authoritative;
    2302             : 
    2303             :         /*
    2304             :          * do we need encryption at the application layer?
    2305             :          */
    2306             :         bool user_encrypt;
    2307             :         bool try_logon_ex;
    2308             :         bool try_validation6;
    2309             : 
    2310             :         /*
    2311             :          * the read only credentials before we started the operation
    2312             :          * used for netr_LogonSamLogonEx() if required (validation_level = 3).
    2313             :          */
    2314             :         struct netlogon_creds_CredentialState *ro_creds;
    2315             : 
    2316             :         /*
    2317             :          * The (locked) credentials used for the credential chain
    2318             :          * used for netr_LogonSamLogonWithFlags() or
    2319             :          * netr_LogonSamLogonWith().
    2320             :          */
    2321             :         struct netlogon_creds_CredentialState *lk_creds;
    2322             : 
    2323             :         /*
    2324             :          * While we have locked the global credentials (lk_creds above)
    2325             :          * we operate an a temporary copy, because a server
    2326             :          * may not support netr_LogonSamLogonWithFlags() and
    2327             :          * didn't process our netr_Authenticator, so we need to
    2328             :          * restart from lk_creds.
    2329             :          */
    2330             :         struct netlogon_creds_CredentialState tmp_creds;
    2331             :         struct netr_Authenticator req_auth;
    2332             :         struct netr_Authenticator rep_auth;
    2333             : };
    2334             : 
    2335             : static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
    2336             : static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
    2337             :                                                      NTSTATUS status);
    2338             : 
    2339          31 : struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
    2340             :                                 struct tevent_context *ev,
    2341             :                                 struct netlogon_creds_cli_context *context,
    2342             :                                 struct dcerpc_binding_handle *b,
    2343             :                                 enum netr_LogonInfoClass logon_level,
    2344             :                                 const union netr_LogonLevel *logon,
    2345             :                                 uint32_t flags)
    2346             : {
    2347             :         struct tevent_req *req;
    2348             :         struct netlogon_creds_cli_LogonSamLogon_state *state;
    2349             : 
    2350          31 :         req = tevent_req_create(mem_ctx, &state,
    2351             :                                 struct netlogon_creds_cli_LogonSamLogon_state);
    2352          31 :         if (req == NULL) {
    2353           0 :                 return NULL;
    2354             :         }
    2355             : 
    2356          31 :         state->ev = ev;
    2357          31 :         state->context = context;
    2358          31 :         state->binding_handle = b;
    2359             : 
    2360          31 :         state->logon_level = logon_level;
    2361          31 :         state->const_logon = logon;
    2362          31 :         state->flags = flags;
    2363             : 
    2364          31 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    2365             :                                                 context->server.computer);
    2366          31 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    2367           0 :                 return tevent_req_post(req, ev);
    2368             :         }
    2369             : 
    2370          31 :         switch (logon_level) {
    2371           3 :         case NetlogonInteractiveInformation:
    2372             :         case NetlogonInteractiveTransitiveInformation:
    2373             :         case NetlogonServiceInformation:
    2374             :         case NetlogonServiceTransitiveInformation:
    2375             :         case NetlogonGenericInformation:
    2376           3 :                 state->user_encrypt = true;
    2377           3 :                 break;
    2378             : 
    2379          28 :         case NetlogonNetworkInformation:
    2380             :         case NetlogonNetworkTransitiveInformation:
    2381          28 :                 break;
    2382             :         }
    2383             : 
    2384          31 :         state->validation = talloc_zero(state, union netr_Validation);
    2385          31 :         if (tevent_req_nomem(state->validation, req)) {
    2386           0 :                 return tevent_req_post(req, ev);
    2387             :         }
    2388             : 
    2389          31 :         netlogon_creds_cli_LogonSamLogon_start(req);
    2390          31 :         if (!tevent_req_is_in_progress(req)) {
    2391           0 :                 return tevent_req_post(req, ev);
    2392             :         }
    2393             : 
    2394             :         /*
    2395             :          * we defer all callbacks in order to cleanup
    2396             :          * the database record.
    2397             :          */
    2398          31 :         tevent_req_defer_callback(req, state->ev);
    2399          31 :         return req;
    2400             : }
    2401             : 
    2402          12 : static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
    2403             :                                                      NTSTATUS status)
    2404             : {
    2405          12 :         struct netlogon_creds_cli_LogonSamLogon_state *state =
    2406          12 :                 tevent_req_data(req,
    2407             :                 struct netlogon_creds_cli_LogonSamLogon_state);
    2408             : 
    2409          12 :         if (state->lk_creds == NULL) {
    2410          12 :                 return;
    2411             :         }
    2412             : 
    2413           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
    2414             :                 /*
    2415             :                  * This is a hack to recover from a bug in old
    2416             :                  * Samba servers, when LogonSamLogonEx() fails:
    2417             :                  *
    2418             :                  * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
    2419             :                  *
    2420             :                  * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
    2421             :                  *
    2422             :                  * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
    2423             :                  * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
    2424             :                  * If the sign/seal check fails.
    2425             :                  *
    2426             :                  * In that case we need to cleanup the netlogon session.
    2427             :                  *
    2428             :                  * It's the job of the caller to disconnect the current
    2429             :                  * connection, if netlogon_creds_cli_LogonSamLogon()
    2430             :                  * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
    2431             :                  */
    2432           0 :                 if (!state->context->server.try_logon_with) {
    2433           0 :                         status = NT_STATUS_NETWORK_ACCESS_DENIED;
    2434             :                 }
    2435             :         }
    2436             : 
    2437           0 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
    2438           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
    2439           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
    2440           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
    2441           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
    2442           0 :                 TALLOC_FREE(state->lk_creds);
    2443           0 :                 return;
    2444             :         }
    2445             : 
    2446           0 :         netlogon_creds_cli_delete(state->context, state->lk_creds);
    2447           0 :         TALLOC_FREE(state->lk_creds);
    2448             : }
    2449             : 
    2450             : static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
    2451             : 
    2452          40 : static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
    2453             : {
    2454          36 :         struct netlogon_creds_cli_LogonSamLogon_state *state =
    2455          40 :                 tevent_req_data(req,
    2456             :                 struct netlogon_creds_cli_LogonSamLogon_state);
    2457             :         struct tevent_req *subreq;
    2458             :         NTSTATUS status;
    2459             :         enum dcerpc_AuthType auth_type;
    2460             :         enum dcerpc_AuthLevel auth_level;
    2461             : 
    2462          40 :         TALLOC_FREE(state->ro_creds);
    2463          40 :         TALLOC_FREE(state->logon);
    2464          40 :         ZERO_STRUCTP(state->validation);
    2465             : 
    2466          40 :         dcerpc_binding_handle_auth_info(state->binding_handle,
    2467             :                                         &auth_type, &auth_level);
    2468             : 
    2469          40 :         state->try_logon_ex = state->context->server.try_logon_ex;
    2470          40 :         state->try_validation6 = state->context->server.try_validation6;
    2471             : 
    2472          40 :         if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
    2473          18 :                 state->try_logon_ex = false;
    2474             :         }
    2475             : 
    2476          40 :         if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
    2477          18 :                 state->try_validation6 = false;
    2478             :         }
    2479             : 
    2480          40 :         if (state->try_logon_ex) {
    2481          22 :                 if (state->try_validation6) {
    2482          22 :                         state->validation_level = 6;
    2483             :                 } else {
    2484           0 :                         state->validation_level = 3;
    2485           0 :                         state->user_encrypt = true;
    2486             :                 }
    2487             : 
    2488          22 :                 state->logon = netlogon_creds_shallow_copy_logon(state,
    2489             :                                                         state->logon_level,
    2490             :                                                         state->const_logon);
    2491          22 :                 if (tevent_req_nomem(state->logon, req)) {
    2492           0 :                         status = NT_STATUS_NO_MEMORY;
    2493           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2494           0 :                         return;
    2495             :                 }
    2496             : 
    2497          22 :                 if (state->user_encrypt) {
    2498           0 :                         status = netlogon_creds_cli_get(state->context,
    2499             :                                                         state,
    2500             :                                                         &state->ro_creds);
    2501           0 :                         if (!NT_STATUS_IS_OK(status)) {
    2502           0 :                                 status = NT_STATUS_ACCESS_DENIED;
    2503           0 :                                 tevent_req_nterror(req, status);
    2504           0 :                                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2505           0 :                                 return;
    2506             :                         }
    2507             : 
    2508           0 :                         status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
    2509             :                                                                        state->logon_level,
    2510             :                                                                        state->logon);
    2511           0 :                         if (!NT_STATUS_IS_OK(status)) {
    2512           0 :                                 status = NT_STATUS_ACCESS_DENIED;
    2513           0 :                                 tevent_req_nterror(req, status);
    2514           0 :                                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2515           0 :                                 return;
    2516             :                         }
    2517             :                 }
    2518             : 
    2519          76 :                 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
    2520             :                                                 state->binding_handle,
    2521          22 :                                                 state->srv_name_slash,
    2522          22 :                                                 state->context->client.computer,
    2523             :                                                 state->logon_level,
    2524             :                                                 state->logon,
    2525          22 :                                                 state->validation_level,
    2526             :                                                 state->validation,
    2527             :                                                 &state->authoritative,
    2528             :                                                 &state->flags);
    2529          22 :                 if (tevent_req_nomem(subreq, req)) {
    2530           0 :                         status = NT_STATUS_NO_MEMORY;
    2531           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2532           0 :                         return;
    2533             :                 }
    2534          22 :                 tevent_req_set_callback(subreq,
    2535             :                                         netlogon_creds_cli_LogonSamLogon_done,
    2536             :                                         req);
    2537          22 :                 return;
    2538             :         }
    2539             : 
    2540          18 :         if (state->lk_creds == NULL) {
    2541           9 :                 subreq = netlogon_creds_cli_lock_send(state, state->ev,
    2542             :                                                       state->context);
    2543           9 :                 if (tevent_req_nomem(subreq, req)) {
    2544           0 :                         status = NT_STATUS_NO_MEMORY;
    2545           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2546           0 :                         return;
    2547             :                 }
    2548           9 :                 tevent_req_set_callback(subreq,
    2549             :                                         netlogon_creds_cli_LogonSamLogon_done,
    2550             :                                         req);
    2551           9 :                 return;
    2552             :         }
    2553             : 
    2554           9 :         state->tmp_creds = *state->lk_creds;
    2555           9 :         status = netlogon_creds_client_authenticator(&state->tmp_creds,
    2556             :                                                      &state->req_auth);
    2557           9 :         if (tevent_req_nterror(req, status)) {
    2558           0 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2559           0 :                 return;
    2560             :         }
    2561           9 :         ZERO_STRUCT(state->rep_auth);
    2562             : 
    2563           9 :         state->logon = netlogon_creds_shallow_copy_logon(state,
    2564             :                                                 state->logon_level,
    2565             :                                                 state->const_logon);
    2566           9 :         if (tevent_req_nomem(state->logon, req)) {
    2567           0 :                 status = NT_STATUS_NO_MEMORY;
    2568           0 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2569           0 :                 return;
    2570             :         }
    2571             : 
    2572           9 :         status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
    2573             :                                                        state->logon_level,
    2574             :                                                        state->logon);
    2575           9 :         if (tevent_req_nterror(req, status)) {
    2576           0 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2577           0 :                 return;
    2578             :         }
    2579             : 
    2580           9 :         state->validation_level = 3;
    2581             : 
    2582           9 :         if (state->context->server.try_logon_with) {
    2583          36 :                 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
    2584             :                                                 state->binding_handle,
    2585           9 :                                                 state->srv_name_slash,
    2586           9 :                                                 state->context->client.computer,
    2587             :                                                 &state->req_auth,
    2588             :                                                 &state->rep_auth,
    2589             :                                                 state->logon_level,
    2590             :                                                 state->logon,
    2591           9 :                                                 state->validation_level,
    2592             :                                                 state->validation,
    2593             :                                                 &state->authoritative,
    2594             :                                                 &state->flags);
    2595           9 :                 if (tevent_req_nomem(subreq, req)) {
    2596           0 :                         status = NT_STATUS_NO_MEMORY;
    2597           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2598           0 :                         return;
    2599             :                 }
    2600             :         } else {
    2601           0 :                 state->flags = 0;
    2602             : 
    2603           0 :                 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
    2604             :                                                 state->binding_handle,
    2605           0 :                                                 state->srv_name_slash,
    2606           0 :                                                 state->context->client.computer,
    2607             :                                                 &state->req_auth,
    2608             :                                                 &state->rep_auth,
    2609             :                                                 state->logon_level,
    2610             :                                                 state->logon,
    2611           0 :                                                 state->validation_level,
    2612             :                                                 state->validation,
    2613             :                                                 &state->authoritative);
    2614           0 :                 if (tevent_req_nomem(subreq, req)) {
    2615           0 :                         status = NT_STATUS_NO_MEMORY;
    2616           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2617           0 :                         return;
    2618             :                 }
    2619             :         }
    2620             : 
    2621           9 :         tevent_req_set_callback(subreq,
    2622             :                                 netlogon_creds_cli_LogonSamLogon_done,
    2623             :                                 req);
    2624             : }
    2625             : 
    2626          40 : static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
    2627             : {
    2628          36 :         struct tevent_req *req =
    2629          40 :                 tevent_req_callback_data(subreq,
    2630             :                 struct tevent_req);
    2631          36 :         struct netlogon_creds_cli_LogonSamLogon_state *state =
    2632          40 :                 tevent_req_data(req,
    2633             :                 struct netlogon_creds_cli_LogonSamLogon_state);
    2634             :         NTSTATUS status;
    2635             :         NTSTATUS result;
    2636             :         bool ok;
    2637             : 
    2638          40 :         if (state->try_logon_ex) {
    2639          22 :                 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
    2640          22 :                                                           state->validation,
    2641             :                                                           &result);
    2642          22 :                 TALLOC_FREE(subreq);
    2643          22 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
    2644           0 :                         state->context->server.try_validation6 = false;
    2645           0 :                         state->context->server.try_logon_ex = false;
    2646           0 :                         netlogon_creds_cli_LogonSamLogon_start(req);
    2647           0 :                         return;
    2648             :                 }
    2649          22 :                 if (tevent_req_nterror(req, status)) {
    2650           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2651           0 :                         return;
    2652             :                 }
    2653             : 
    2654          40 :                 if ((state->validation_level == 6) &&
    2655          40 :                     (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
    2656          40 :                      NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
    2657          22 :                      NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
    2658             :                 {
    2659           0 :                         state->context->server.try_validation6 = false;
    2660           0 :                         netlogon_creds_cli_LogonSamLogon_start(req);
    2661           0 :                         return;
    2662             :                 }
    2663             : 
    2664          22 :                 if (tevent_req_nterror(req, result)) {
    2665           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
    2666           0 :                         return;
    2667             :                 }
    2668             : 
    2669          22 :                 if (state->ro_creds == NULL) {
    2670          22 :                         tevent_req_done(req);
    2671          22 :                         return;
    2672             :                 }
    2673             : 
    2674           0 :                 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
    2675           0 :                 if (!ok) {
    2676             :                         /*
    2677             :                          * We got a race, lets retry with on authenticator
    2678             :                          * protection.
    2679             :                          *
    2680             :                          * netlogon_creds_cli_LogonSamLogon_start()
    2681             :                          * will TALLOC_FREE(state->ro_creds);
    2682             :                          */
    2683           0 :                         state->try_logon_ex = false;
    2684           0 :                         netlogon_creds_cli_LogonSamLogon_start(req);
    2685           0 :                         return;
    2686             :                 }
    2687             : 
    2688           0 :                 status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
    2689           0 :                                                                     state->validation_level,
    2690             :                                                                     state->validation);
    2691           0 :                 if (tevent_req_nterror(req, status)) {
    2692           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2693           0 :                         return;
    2694             :                 }
    2695             : 
    2696           0 :                 tevent_req_done(req);
    2697           0 :                 return;
    2698             :         }
    2699             : 
    2700          18 :         if (state->lk_creds == NULL) {
    2701           9 :                 status = netlogon_creds_cli_lock_recv(subreq, state,
    2702             :                                                       &state->lk_creds);
    2703           9 :                 TALLOC_FREE(subreq);
    2704           9 :                 if (tevent_req_nterror(req, status)) {
    2705           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2706           0 :                         return;
    2707             :                 }
    2708             : 
    2709           9 :                 netlogon_creds_cli_LogonSamLogon_start(req);
    2710           9 :                 return;
    2711             :         }
    2712             : 
    2713           9 :         if (state->context->server.try_logon_with) {
    2714           9 :                 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
    2715           9 :                                                                  state->validation,
    2716             :                                                                  &result);
    2717           9 :                 TALLOC_FREE(subreq);
    2718           9 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
    2719           0 :                         state->context->server.try_logon_with = false;
    2720           0 :                         netlogon_creds_cli_LogonSamLogon_start(req);
    2721           0 :                         return;
    2722             :                 }
    2723           9 :                 if (tevent_req_nterror(req, status)) {
    2724           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2725           0 :                         return;
    2726             :                 }
    2727             :         } else {
    2728           0 :                 status = dcerpc_netr_LogonSamLogon_recv(subreq,
    2729           0 :                                                         state->validation,
    2730             :                                                         &result);
    2731           0 :                 TALLOC_FREE(subreq);
    2732           0 :                 if (tevent_req_nterror(req, status)) {
    2733           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2734           0 :                         return;
    2735             :                 }
    2736             :         }
    2737             : 
    2738           9 :         ok = netlogon_creds_client_check(&state->tmp_creds,
    2739           9 :                                          &state->rep_auth.cred);
    2740           9 :         if (!ok) {
    2741           0 :                 status = NT_STATUS_ACCESS_DENIED;
    2742           0 :                 tevent_req_nterror(req, status);
    2743           0 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2744           0 :                 return;
    2745             :         }
    2746             : 
    2747           9 :         *state->lk_creds = state->tmp_creds;
    2748           9 :         status = netlogon_creds_cli_store(state->context,
    2749             :                                           state->lk_creds);
    2750           9 :         TALLOC_FREE(state->lk_creds);
    2751             : 
    2752           9 :         if (tevent_req_nterror(req, status)) {
    2753           0 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2754           0 :                 return;
    2755             :         }
    2756             : 
    2757           9 :         if (tevent_req_nterror(req, result)) {
    2758           6 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
    2759           6 :                 return;
    2760             :         }
    2761             : 
    2762           6 :         status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
    2763           3 :                                                             state->validation_level,
    2764             :                                                             state->validation);
    2765           3 :         if (tevent_req_nterror(req, status)) {
    2766           0 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
    2767           0 :                 return;
    2768             :         }
    2769             : 
    2770           3 :         tevent_req_done(req);
    2771             : }
    2772             : 
    2773          31 : NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
    2774             :                                         TALLOC_CTX *mem_ctx,
    2775             :                                         uint16_t *validation_level,
    2776             :                                         union netr_Validation **validation,
    2777             :                                         uint8_t *authoritative,
    2778             :                                         uint32_t *flags)
    2779             : {
    2780          27 :         struct netlogon_creds_cli_LogonSamLogon_state *state =
    2781          31 :                 tevent_req_data(req,
    2782             :                 struct netlogon_creds_cli_LogonSamLogon_state);
    2783             :         NTSTATUS status;
    2784             : 
    2785             :         /* authoritative is also returned on error */
    2786          31 :         *authoritative = state->authoritative;
    2787             : 
    2788          31 :         if (tevent_req_is_nterror(req, &status)) {
    2789           6 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2790           6 :                 tevent_req_received(req);
    2791           6 :                 return status;
    2792             :         }
    2793             : 
    2794          25 :         *validation_level = state->validation_level;
    2795          25 :         *validation = talloc_move(mem_ctx, &state->validation);
    2796          25 :         *flags = state->flags;
    2797             : 
    2798          25 :         tevent_req_received(req);
    2799          25 :         return NT_STATUS_OK;
    2800             : }
    2801             : 
    2802          31 : NTSTATUS netlogon_creds_cli_LogonSamLogon(
    2803             :                                 struct netlogon_creds_cli_context *context,
    2804             :                                 struct dcerpc_binding_handle *b,
    2805             :                                 enum netr_LogonInfoClass logon_level,
    2806             :                                 const union netr_LogonLevel *logon,
    2807             :                                 TALLOC_CTX *mem_ctx,
    2808             :                                 uint16_t *validation_level,
    2809             :                                 union netr_Validation **validation,
    2810             :                                 uint8_t *authoritative,
    2811             :                                 uint32_t *flags)
    2812             : {
    2813          31 :         TALLOC_CTX *frame = talloc_stackframe();
    2814             :         struct tevent_context *ev;
    2815             :         struct tevent_req *req;
    2816          31 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    2817             : 
    2818          31 :         ev = samba_tevent_context_init(frame);
    2819          31 :         if (ev == NULL) {
    2820           0 :                 goto fail;
    2821             :         }
    2822          31 :         req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
    2823             :                                                     logon_level, logon,
    2824             :                                                     *flags);
    2825          31 :         if (req == NULL) {
    2826           0 :                 goto fail;
    2827             :         }
    2828          31 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    2829           0 :                 goto fail;
    2830             :         }
    2831          31 :         status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
    2832             :                                                        validation_level,
    2833             :                                                        validation,
    2834             :                                                        authoritative,
    2835             :                                                        flags);
    2836          31 :  fail:
    2837          31 :         TALLOC_FREE(frame);
    2838          31 :         return status;
    2839             : }
    2840             : 
    2841             : struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
    2842             :         struct tevent_context *ev;
    2843             :         struct netlogon_creds_cli_context *context;
    2844             :         struct dcerpc_binding_handle *binding_handle;
    2845             : 
    2846             :         char *srv_name_slash;
    2847             :         enum dcerpc_AuthType auth_type;
    2848             :         enum dcerpc_AuthLevel auth_level;
    2849             : 
    2850             :         const char *site_name;
    2851             :         uint32_t dns_ttl;
    2852             :         struct NL_DNS_NAME_INFO_ARRAY *dns_names;
    2853             : 
    2854             :         struct netlogon_creds_CredentialState *creds;
    2855             :         struct netlogon_creds_CredentialState tmp_creds;
    2856             :         struct netr_Authenticator req_auth;
    2857             :         struct netr_Authenticator rep_auth;
    2858             : };
    2859             : 
    2860             : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
    2861             :                                                      NTSTATUS status);
    2862             : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
    2863             : 
    2864           0 : struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
    2865             :                                                                              struct tevent_context *ev,
    2866             :                                                                              struct netlogon_creds_cli_context *context,
    2867             :                                                                              struct dcerpc_binding_handle *b,
    2868             :                                                                              const char *site_name,
    2869             :                                                                              uint32_t dns_ttl,
    2870             :                                                                              struct NL_DNS_NAME_INFO_ARRAY *dns_names)
    2871             : {
    2872             :         struct tevent_req *req;
    2873             :         struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
    2874             :         struct tevent_req *subreq;
    2875             : 
    2876           0 :         req = tevent_req_create(mem_ctx, &state,
    2877             :                                 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
    2878           0 :         if (req == NULL) {
    2879           0 :                 return NULL;
    2880             :         }
    2881             : 
    2882           0 :         state->ev = ev;
    2883           0 :         state->context = context;
    2884           0 :         state->binding_handle = b;
    2885             : 
    2886           0 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    2887             :                                                 context->server.computer);
    2888           0 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    2889           0 :                 return tevent_req_post(req, ev);
    2890             :         }
    2891             : 
    2892           0 :         state->site_name = site_name;
    2893           0 :         state->dns_ttl = dns_ttl;
    2894           0 :         state->dns_names = dns_names;
    2895             : 
    2896           0 :         dcerpc_binding_handle_auth_info(state->binding_handle,
    2897           0 :                                         &state->auth_type,
    2898           0 :                                         &state->auth_level);
    2899             : 
    2900           0 :         subreq = netlogon_creds_cli_lock_send(state, state->ev,
    2901           0 :                                               state->context);
    2902           0 :         if (tevent_req_nomem(subreq, req)) {
    2903           0 :                 return tevent_req_post(req, ev);
    2904             :         }
    2905             : 
    2906           0 :         tevent_req_set_callback(subreq,
    2907             :                                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
    2908             :                                 req);
    2909             : 
    2910           0 :         return req;
    2911             : }
    2912             : 
    2913           0 : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
    2914             :                                                          NTSTATUS status)
    2915             : {
    2916           0 :         struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
    2917           0 :                 tevent_req_data(req,
    2918             :                 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
    2919             : 
    2920           0 :         if (state->creds == NULL) {
    2921           0 :                 return;
    2922             :         }
    2923             : 
    2924           0 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
    2925           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
    2926           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
    2927           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
    2928           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
    2929           0 :                 TALLOC_FREE(state->creds);
    2930           0 :                 return;
    2931             :         }
    2932             : 
    2933           0 :         netlogon_creds_cli_delete(state->context, state->creds);
    2934           0 :         TALLOC_FREE(state->creds);
    2935             : }
    2936             : 
    2937             : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
    2938             : 
    2939           0 : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
    2940             : {
    2941           0 :         struct tevent_req *req =
    2942           0 :                 tevent_req_callback_data(subreq,
    2943             :                 struct tevent_req);
    2944           0 :         struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
    2945           0 :                 tevent_req_data(req,
    2946             :                 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
    2947             :         NTSTATUS status;
    2948             : 
    2949           0 :         status = netlogon_creds_cli_lock_recv(subreq, state,
    2950             :                                               &state->creds);
    2951           0 :         TALLOC_FREE(subreq);
    2952           0 :         if (tevent_req_nterror(req, status)) {
    2953           0 :                 return;
    2954             :         }
    2955             : 
    2956           0 :         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
    2957           0 :                 switch (state->auth_level) {
    2958           0 :                 case DCERPC_AUTH_LEVEL_INTEGRITY:
    2959             :                 case DCERPC_AUTH_LEVEL_PRIVACY:
    2960           0 :                         break;
    2961           0 :                 default:
    2962           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    2963           0 :                         return;
    2964             :                 }
    2965             :         } else {
    2966           0 :                 uint32_t tmp = state->creds->negotiate_flags;
    2967             : 
    2968           0 :                 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
    2969             :                         /*
    2970             :                          * if DCERPC_AUTH_TYPE_SCHANNEL is supported
    2971             :                          * it should be used, which means
    2972             :                          * we had a chance to verify no downgrade
    2973             :                          * happened.
    2974             :                          *
    2975             :                          * This relies on netlogon_creds_cli_check*
    2976             :                          * being called before, as first request after
    2977             :                          * the DCERPC bind.
    2978             :                          */
    2979           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    2980           0 :                         return;
    2981             :                 }
    2982             :         }
    2983             : 
    2984             :         /*
    2985             :          * we defer all callbacks in order to cleanup
    2986             :          * the database record.
    2987             :          */
    2988           0 :         tevent_req_defer_callback(req, state->ev);
    2989             : 
    2990           0 :         state->tmp_creds = *state->creds;
    2991           0 :         status = netlogon_creds_client_authenticator(&state->tmp_creds,
    2992             :                                                      &state->req_auth);
    2993           0 :         if (tevent_req_nterror(req, status)) {
    2994           0 :                 return;
    2995             :         }
    2996           0 :         ZERO_STRUCT(state->rep_auth);
    2997             : 
    2998           0 :         subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
    2999             :                                                                     state->binding_handle,
    3000           0 :                                                                     state->srv_name_slash,
    3001             :                                                                     state->tmp_creds.computer_name,
    3002             :                                                                     &state->req_auth,
    3003             :                                                                     &state->rep_auth,
    3004             :                                                                     state->site_name,
    3005             :                                                                     state->dns_ttl,
    3006             :                                                                     state->dns_names);
    3007           0 :         if (tevent_req_nomem(subreq, req)) {
    3008           0 :                 status = NT_STATUS_NO_MEMORY;
    3009           0 :                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
    3010           0 :                 return;
    3011             :         }
    3012             : 
    3013           0 :         tevent_req_set_callback(subreq,
    3014             :                                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
    3015             :                                 req);
    3016             : }
    3017             : 
    3018           0 : static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
    3019             : {
    3020           0 :         struct tevent_req *req =
    3021           0 :                 tevent_req_callback_data(subreq,
    3022             :                 struct tevent_req);
    3023           0 :         struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
    3024           0 :                 tevent_req_data(req,
    3025             :                 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
    3026             :         NTSTATUS status;
    3027             :         NTSTATUS result;
    3028             :         bool ok;
    3029             : 
    3030             :         /*
    3031             :          * We use state->dns_names as the memory context, as this is
    3032             :          * the only in/out variable and it has been overwritten by the
    3033             :          * out parameter from the server.
    3034             :          *
    3035             :          * We need to preserve the return value until the caller can use it.
    3036             :          */
    3037           0 :         status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
    3038             :                                                                     &result);
    3039           0 :         TALLOC_FREE(subreq);
    3040           0 :         if (tevent_req_nterror(req, status)) {
    3041           0 :                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
    3042           0 :                 return;
    3043             :         }
    3044             : 
    3045           0 :         ok = netlogon_creds_client_check(&state->tmp_creds,
    3046           0 :                                          &state->rep_auth.cred);
    3047           0 :         if (!ok) {
    3048           0 :                 status = NT_STATUS_ACCESS_DENIED;
    3049           0 :                 tevent_req_nterror(req, status);
    3050           0 :                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
    3051           0 :                 return;
    3052             :         }
    3053             : 
    3054           0 :         *state->creds = state->tmp_creds;
    3055           0 :         status = netlogon_creds_cli_store(state->context,
    3056             :                                           state->creds);
    3057           0 :         TALLOC_FREE(state->creds);
    3058             : 
    3059           0 :         if (tevent_req_nterror(req, status)) {
    3060           0 :                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
    3061           0 :                 return;
    3062             :         }
    3063             : 
    3064           0 :         if (tevent_req_nterror(req, result)) {
    3065           0 :                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
    3066           0 :                 return;
    3067             :         }
    3068             : 
    3069           0 :         tevent_req_done(req);
    3070             : }
    3071             : 
    3072           0 : NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
    3073             : {
    3074             :         NTSTATUS status;
    3075             : 
    3076           0 :         if (tevent_req_is_nterror(req, &status)) {
    3077           0 :                 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
    3078           0 :                 tevent_req_received(req);
    3079           0 :                 return status;
    3080             :         }
    3081             : 
    3082           0 :         tevent_req_received(req);
    3083           0 :         return NT_STATUS_OK;
    3084             : }
    3085             : 
    3086           0 : NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
    3087             :                                 struct netlogon_creds_cli_context *context,
    3088             :                                 struct dcerpc_binding_handle *b,
    3089             :                                 const char *site_name,
    3090             :                                 uint32_t dns_ttl,
    3091             :                                 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
    3092             : {
    3093           0 :         TALLOC_CTX *frame = talloc_stackframe();
    3094             :         struct tevent_context *ev;
    3095             :         struct tevent_req *req;
    3096           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    3097             : 
    3098           0 :         ev = samba_tevent_context_init(frame);
    3099           0 :         if (ev == NULL) {
    3100           0 :                 goto fail;
    3101             :         }
    3102           0 :         req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
    3103             :                                                                         site_name,
    3104             :                                                                         dns_ttl,
    3105             :                                                                         dns_names);
    3106           0 :         if (req == NULL) {
    3107           0 :                 goto fail;
    3108             :         }
    3109           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    3110           0 :                 goto fail;
    3111             :         }
    3112           0 :         status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
    3113           0 :  fail:
    3114           0 :         TALLOC_FREE(frame);
    3115           0 :         return status;
    3116             : }
    3117             : 
    3118             : struct netlogon_creds_cli_ServerGetTrustInfo_state {
    3119             :         struct tevent_context *ev;
    3120             :         struct netlogon_creds_cli_context *context;
    3121             :         struct dcerpc_binding_handle *binding_handle;
    3122             : 
    3123             :         char *srv_name_slash;
    3124             :         enum dcerpc_AuthType auth_type;
    3125             :         enum dcerpc_AuthLevel auth_level;
    3126             : 
    3127             :         struct samr_Password new_owf_password;
    3128             :         struct samr_Password old_owf_password;
    3129             :         struct netr_TrustInfo *trust_info;
    3130             : 
    3131             :         struct netlogon_creds_CredentialState *creds;
    3132             :         struct netlogon_creds_CredentialState tmp_creds;
    3133             :         struct netr_Authenticator req_auth;
    3134             :         struct netr_Authenticator rep_auth;
    3135             : };
    3136             : 
    3137             : static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
    3138             :                                                      NTSTATUS status);
    3139             : static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
    3140             : 
    3141           0 : struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
    3142             :                                         struct tevent_context *ev,
    3143             :                                         struct netlogon_creds_cli_context *context,
    3144             :                                         struct dcerpc_binding_handle *b)
    3145             : {
    3146             :         struct tevent_req *req;
    3147             :         struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
    3148             :         struct tevent_req *subreq;
    3149             : 
    3150           0 :         req = tevent_req_create(mem_ctx, &state,
    3151             :                                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
    3152           0 :         if (req == NULL) {
    3153           0 :                 return NULL;
    3154             :         }
    3155             : 
    3156           0 :         state->ev = ev;
    3157           0 :         state->context = context;
    3158           0 :         state->binding_handle = b;
    3159             : 
    3160           0 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    3161             :                                                 context->server.computer);
    3162           0 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    3163           0 :                 return tevent_req_post(req, ev);
    3164             :         }
    3165             : 
    3166           0 :         dcerpc_binding_handle_auth_info(state->binding_handle,
    3167           0 :                                         &state->auth_type,
    3168           0 :                                         &state->auth_level);
    3169             : 
    3170           0 :         subreq = netlogon_creds_cli_lock_send(state, state->ev,
    3171           0 :                                               state->context);
    3172           0 :         if (tevent_req_nomem(subreq, req)) {
    3173           0 :                 return tevent_req_post(req, ev);
    3174             :         }
    3175             : 
    3176           0 :         tevent_req_set_callback(subreq,
    3177             :                                 netlogon_creds_cli_ServerGetTrustInfo_locked,
    3178             :                                 req);
    3179             : 
    3180           0 :         return req;
    3181             : }
    3182             : 
    3183           0 : static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
    3184             :                                                          NTSTATUS status)
    3185             : {
    3186           0 :         struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
    3187           0 :                 tevent_req_data(req,
    3188             :                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
    3189             : 
    3190           0 :         if (state->creds == NULL) {
    3191           0 :                 return;
    3192             :         }
    3193             : 
    3194           0 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
    3195           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
    3196           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
    3197           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
    3198           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
    3199           0 :                 TALLOC_FREE(state->creds);
    3200           0 :                 return;
    3201             :         }
    3202             : 
    3203           0 :         netlogon_creds_cli_delete(state->context, state->creds);
    3204           0 :         TALLOC_FREE(state->creds);
    3205             : }
    3206             : 
    3207             : static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
    3208             : 
    3209           0 : static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
    3210             : {
    3211           0 :         struct tevent_req *req =
    3212           0 :                 tevent_req_callback_data(subreq,
    3213             :                 struct tevent_req);
    3214           0 :         struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
    3215           0 :                 tevent_req_data(req,
    3216             :                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
    3217             :         NTSTATUS status;
    3218             : 
    3219           0 :         status = netlogon_creds_cli_lock_recv(subreq, state,
    3220             :                                               &state->creds);
    3221           0 :         TALLOC_FREE(subreq);
    3222           0 :         if (tevent_req_nterror(req, status)) {
    3223           0 :                 return;
    3224             :         }
    3225             : 
    3226           0 :         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
    3227           0 :                 switch (state->auth_level) {
    3228           0 :                 case DCERPC_AUTH_LEVEL_PRIVACY:
    3229           0 :                         break;
    3230           0 :                 default:
    3231           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    3232           0 :                         return;
    3233             :                 }
    3234             :         } else {
    3235           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    3236           0 :                 return;
    3237             :         }
    3238             : 
    3239             :         /*
    3240             :          * we defer all callbacks in order to cleanup
    3241             :          * the database record.
    3242             :          */
    3243           0 :         tevent_req_defer_callback(req, state->ev);
    3244             : 
    3245           0 :         state->tmp_creds = *state->creds;
    3246           0 :         status = netlogon_creds_client_authenticator(&state->tmp_creds,
    3247             :                                                      &state->req_auth);
    3248           0 :         if (tevent_req_nterror(req, status)) {
    3249           0 :                 return;
    3250             :         }
    3251           0 :         ZERO_STRUCT(state->rep_auth);
    3252             : 
    3253           0 :         subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
    3254             :                                                      state->binding_handle,
    3255           0 :                                                      state->srv_name_slash,
    3256             :                                                      state->tmp_creds.account_name,
    3257             :                                                      state->tmp_creds.secure_channel_type,
    3258             :                                                      state->tmp_creds.computer_name,
    3259             :                                                      &state->req_auth,
    3260             :                                                      &state->rep_auth,
    3261             :                                                      &state->new_owf_password,
    3262             :                                                      &state->old_owf_password,
    3263             :                                                      &state->trust_info);
    3264           0 :         if (tevent_req_nomem(subreq, req)) {
    3265           0 :                 status = NT_STATUS_NO_MEMORY;
    3266           0 :                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
    3267           0 :                 return;
    3268             :         }
    3269             : 
    3270           0 :         tevent_req_set_callback(subreq,
    3271             :                                 netlogon_creds_cli_ServerGetTrustInfo_done,
    3272             :                                 req);
    3273             : }
    3274             : 
    3275           0 : static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
    3276             : {
    3277           0 :         struct tevent_req *req =
    3278           0 :                 tevent_req_callback_data(subreq,
    3279             :                 struct tevent_req);
    3280           0 :         struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
    3281           0 :                 tevent_req_data(req,
    3282             :                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
    3283             :         NTSTATUS status;
    3284             :         NTSTATUS result;
    3285           0 :         const struct samr_Password zero = {};
    3286             :         bool cmp;
    3287             :         bool ok;
    3288             : 
    3289             :         /*
    3290             :          * We use state->dns_names as the memory context, as this is
    3291             :          * the only in/out variable and it has been overwritten by the
    3292             :          * out parameter from the server.
    3293             :          *
    3294             :          * We need to preserve the return value until the caller can use it.
    3295             :          */
    3296           0 :         status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
    3297           0 :         TALLOC_FREE(subreq);
    3298           0 :         if (tevent_req_nterror(req, status)) {
    3299           0 :                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
    3300           0 :                 return;
    3301             :         }
    3302             : 
    3303           0 :         ok = netlogon_creds_client_check(&state->tmp_creds,
    3304           0 :                                          &state->rep_auth.cred);
    3305           0 :         if (!ok) {
    3306           0 :                 status = NT_STATUS_ACCESS_DENIED;
    3307           0 :                 tevent_req_nterror(req, status);
    3308           0 :                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
    3309           0 :                 return;
    3310             :         }
    3311             : 
    3312           0 :         cmp = mem_equal_const_time(state->new_owf_password.hash,
    3313             :                                    zero.hash, sizeof(zero.hash));
    3314           0 :         if (!cmp) {
    3315           0 :                 status = netlogon_creds_des_decrypt(&state->tmp_creds,
    3316             :                                                     &state->new_owf_password);
    3317           0 :                 if (tevent_req_nterror(req, status)) {
    3318           0 :                         netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
    3319           0 :                         return;
    3320             :                 }
    3321             :         }
    3322           0 :         cmp = mem_equal_const_time(state->old_owf_password.hash,
    3323             :                                    zero.hash, sizeof(zero.hash));
    3324           0 :         if (!cmp) {
    3325           0 :                 status = netlogon_creds_des_decrypt(&state->tmp_creds,
    3326             :                                                     &state->old_owf_password);
    3327           0 :                 if (tevent_req_nterror(req, status)) {
    3328           0 :                         netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
    3329           0 :                         return;
    3330             :                 }
    3331             :         }
    3332             : 
    3333           0 :         *state->creds = state->tmp_creds;
    3334           0 :         status = netlogon_creds_cli_store(state->context,
    3335             :                                           state->creds);
    3336           0 :         TALLOC_FREE(state->creds);
    3337           0 :         if (tevent_req_nterror(req, status)) {
    3338           0 :                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
    3339           0 :                 return;
    3340             :         }
    3341             : 
    3342           0 :         if (tevent_req_nterror(req, result)) {
    3343           0 :                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
    3344           0 :                 return;
    3345             :         }
    3346             : 
    3347           0 :         tevent_req_done(req);
    3348             : }
    3349             : 
    3350           0 : NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
    3351             :                                         TALLOC_CTX *mem_ctx,
    3352             :                                         struct samr_Password *new_owf_password,
    3353             :                                         struct samr_Password *old_owf_password,
    3354             :                                         struct netr_TrustInfo **trust_info)
    3355             : {
    3356           0 :         struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
    3357           0 :                 tevent_req_data(req,
    3358             :                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
    3359             :         NTSTATUS status;
    3360             : 
    3361           0 :         if (tevent_req_is_nterror(req, &status)) {
    3362           0 :                 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
    3363           0 :                 tevent_req_received(req);
    3364           0 :                 return status;
    3365             :         }
    3366             : 
    3367           0 :         if (new_owf_password != NULL) {
    3368           0 :                 *new_owf_password = state->new_owf_password;
    3369             :         }
    3370           0 :         if (old_owf_password != NULL) {
    3371           0 :                 *old_owf_password = state->old_owf_password;
    3372             :         }
    3373           0 :         if (trust_info != NULL) {
    3374           0 :                 *trust_info = talloc_move(mem_ctx, &state->trust_info);
    3375             :         }
    3376             : 
    3377           0 :         tevent_req_received(req);
    3378           0 :         return NT_STATUS_OK;
    3379             : }
    3380             : 
    3381           0 : NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
    3382             :                                 struct netlogon_creds_cli_context *context,
    3383             :                                 struct dcerpc_binding_handle *b,
    3384             :                                 TALLOC_CTX *mem_ctx,
    3385             :                                 struct samr_Password *new_owf_password,
    3386             :                                 struct samr_Password *old_owf_password,
    3387             :                                 struct netr_TrustInfo **trust_info)
    3388             : {
    3389           0 :         TALLOC_CTX *frame = talloc_stackframe();
    3390             :         struct tevent_context *ev;
    3391             :         struct tevent_req *req;
    3392           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    3393             : 
    3394           0 :         ev = samba_tevent_context_init(frame);
    3395           0 :         if (ev == NULL) {
    3396           0 :                 goto fail;
    3397             :         }
    3398           0 :         req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
    3399           0 :         if (req == NULL) {
    3400           0 :                 goto fail;
    3401             :         }
    3402           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    3403           0 :                 goto fail;
    3404             :         }
    3405           0 :         status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
    3406             :                                                             mem_ctx,
    3407             :                                                             new_owf_password,
    3408             :                                                             old_owf_password,
    3409             :                                                             trust_info);
    3410           0 :  fail:
    3411           0 :         TALLOC_FREE(frame);
    3412           0 :         return status;
    3413             : }
    3414             : 
    3415             : struct netlogon_creds_cli_GetForestTrustInformation_state {
    3416             :         struct tevent_context *ev;
    3417             :         struct netlogon_creds_cli_context *context;
    3418             :         struct dcerpc_binding_handle *binding_handle;
    3419             : 
    3420             :         char *srv_name_slash;
    3421             :         enum dcerpc_AuthType auth_type;
    3422             :         enum dcerpc_AuthLevel auth_level;
    3423             : 
    3424             :         uint32_t flags;
    3425             :         struct lsa_ForestTrustInformation *forest_trust_info;
    3426             : 
    3427             :         struct netlogon_creds_CredentialState *creds;
    3428             :         struct netlogon_creds_CredentialState tmp_creds;
    3429             :         struct netr_Authenticator req_auth;
    3430             :         struct netr_Authenticator rep_auth;
    3431             : };
    3432             : 
    3433             : static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
    3434             :                                                      NTSTATUS status);
    3435             : static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
    3436             : 
    3437           0 : struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
    3438             :                                         struct tevent_context *ev,
    3439             :                                         struct netlogon_creds_cli_context *context,
    3440             :                                         struct dcerpc_binding_handle *b)
    3441             : {
    3442             :         struct tevent_req *req;
    3443             :         struct netlogon_creds_cli_GetForestTrustInformation_state *state;
    3444             :         struct tevent_req *subreq;
    3445             : 
    3446           0 :         req = tevent_req_create(mem_ctx, &state,
    3447             :                                 struct netlogon_creds_cli_GetForestTrustInformation_state);
    3448           0 :         if (req == NULL) {
    3449           0 :                 return NULL;
    3450             :         }
    3451             : 
    3452           0 :         state->ev = ev;
    3453           0 :         state->context = context;
    3454           0 :         state->binding_handle = b;
    3455             : 
    3456           0 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    3457             :                                                 context->server.computer);
    3458           0 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    3459           0 :                 return tevent_req_post(req, ev);
    3460             :         }
    3461             : 
    3462           0 :         state->flags = 0;
    3463             : 
    3464           0 :         dcerpc_binding_handle_auth_info(state->binding_handle,
    3465           0 :                                         &state->auth_type,
    3466           0 :                                         &state->auth_level);
    3467             : 
    3468           0 :         subreq = netlogon_creds_cli_lock_send(state, state->ev,
    3469           0 :                                               state->context);
    3470           0 :         if (tevent_req_nomem(subreq, req)) {
    3471           0 :                 return tevent_req_post(req, ev);
    3472             :         }
    3473             : 
    3474           0 :         tevent_req_set_callback(subreq,
    3475             :                                 netlogon_creds_cli_GetForestTrustInformation_locked,
    3476             :                                 req);
    3477             : 
    3478           0 :         return req;
    3479             : }
    3480             : 
    3481           0 : static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
    3482             :                                                          NTSTATUS status)
    3483             : {
    3484           0 :         struct netlogon_creds_cli_GetForestTrustInformation_state *state =
    3485           0 :                 tevent_req_data(req,
    3486             :                 struct netlogon_creds_cli_GetForestTrustInformation_state);
    3487             : 
    3488           0 :         if (state->creds == NULL) {
    3489           0 :                 return;
    3490             :         }
    3491             : 
    3492           0 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
    3493           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
    3494           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
    3495           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
    3496           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
    3497           0 :                 TALLOC_FREE(state->creds);
    3498           0 :                 return;
    3499             :         }
    3500             : 
    3501           0 :         netlogon_creds_cli_delete(state->context, state->creds);
    3502           0 :         TALLOC_FREE(state->creds);
    3503             : }
    3504             : 
    3505             : static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
    3506             : 
    3507           0 : static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
    3508             : {
    3509           0 :         struct tevent_req *req =
    3510           0 :                 tevent_req_callback_data(subreq,
    3511             :                 struct tevent_req);
    3512           0 :         struct netlogon_creds_cli_GetForestTrustInformation_state *state =
    3513           0 :                 tevent_req_data(req,
    3514             :                 struct netlogon_creds_cli_GetForestTrustInformation_state);
    3515             :         NTSTATUS status;
    3516             : 
    3517           0 :         status = netlogon_creds_cli_lock_recv(subreq, state,
    3518             :                                               &state->creds);
    3519           0 :         TALLOC_FREE(subreq);
    3520           0 :         if (tevent_req_nterror(req, status)) {
    3521           0 :                 return;
    3522             :         }
    3523             : 
    3524           0 :         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
    3525           0 :                 switch (state->auth_level) {
    3526           0 :                 case DCERPC_AUTH_LEVEL_INTEGRITY:
    3527             :                 case DCERPC_AUTH_LEVEL_PRIVACY:
    3528           0 :                         break;
    3529           0 :                 default:
    3530           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    3531           0 :                         return;
    3532             :                 }
    3533             :         } else {
    3534           0 :                 uint32_t tmp = state->creds->negotiate_flags;
    3535             : 
    3536           0 :                 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
    3537             :                         /*
    3538             :                          * if DCERPC_AUTH_TYPE_SCHANNEL is supported
    3539             :                          * it should be used, which means
    3540             :                          * we had a chance to verify no downgrade
    3541             :                          * happened.
    3542             :                          *
    3543             :                          * This relies on netlogon_creds_cli_check*
    3544             :                          * being called before, as first request after
    3545             :                          * the DCERPC bind.
    3546             :                          */
    3547           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    3548           0 :                         return;
    3549             :                 }
    3550             :         }
    3551             : 
    3552             :         /*
    3553             :          * we defer all callbacks in order to cleanup
    3554             :          * the database record.
    3555             :          */
    3556           0 :         tevent_req_defer_callback(req, state->ev);
    3557             : 
    3558           0 :         state->tmp_creds = *state->creds;
    3559           0 :         status = netlogon_creds_client_authenticator(&state->tmp_creds,
    3560             :                                                      &state->req_auth);
    3561           0 :         if (tevent_req_nterror(req, status)) {
    3562           0 :                 return;
    3563             :         }
    3564           0 :         ZERO_STRUCT(state->rep_auth);
    3565             : 
    3566           0 :         subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
    3567             :                                                 state->binding_handle,
    3568           0 :                                                 state->srv_name_slash,
    3569             :                                                 state->tmp_creds.computer_name,
    3570             :                                                 &state->req_auth,
    3571             :                                                 &state->rep_auth,
    3572             :                                                 state->flags,
    3573             :                                                 &state->forest_trust_info);
    3574           0 :         if (tevent_req_nomem(subreq, req)) {
    3575           0 :                 status = NT_STATUS_NO_MEMORY;
    3576           0 :                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
    3577           0 :                 return;
    3578             :         }
    3579             : 
    3580           0 :         tevent_req_set_callback(subreq,
    3581             :                                 netlogon_creds_cli_GetForestTrustInformation_done,
    3582             :                                 req);
    3583             : }
    3584             : 
    3585           0 : static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
    3586             : {
    3587           0 :         struct tevent_req *req =
    3588           0 :                 tevent_req_callback_data(subreq,
    3589             :                 struct tevent_req);
    3590           0 :         struct netlogon_creds_cli_GetForestTrustInformation_state *state =
    3591           0 :                 tevent_req_data(req,
    3592             :                 struct netlogon_creds_cli_GetForestTrustInformation_state);
    3593             :         NTSTATUS status;
    3594             :         NTSTATUS result;
    3595             :         bool ok;
    3596             : 
    3597             :         /*
    3598             :          * We use state->dns_names as the memory context, as this is
    3599             :          * the only in/out variable and it has been overwritten by the
    3600             :          * out parameter from the server.
    3601             :          *
    3602             :          * We need to preserve the return value until the caller can use it.
    3603             :          */
    3604           0 :         status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
    3605           0 :         TALLOC_FREE(subreq);
    3606           0 :         if (tevent_req_nterror(req, status)) {
    3607           0 :                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
    3608           0 :                 return;
    3609             :         }
    3610             : 
    3611           0 :         ok = netlogon_creds_client_check(&state->tmp_creds,
    3612           0 :                                          &state->rep_auth.cred);
    3613           0 :         if (!ok) {
    3614           0 :                 status = NT_STATUS_ACCESS_DENIED;
    3615           0 :                 tevent_req_nterror(req, status);
    3616           0 :                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
    3617           0 :                 return;
    3618             :         }
    3619             : 
    3620           0 :         *state->creds = state->tmp_creds;
    3621           0 :         status = netlogon_creds_cli_store(state->context,
    3622             :                                           state->creds);
    3623           0 :         TALLOC_FREE(state->creds);
    3624             : 
    3625           0 :         if (tevent_req_nterror(req, status)) {
    3626           0 :                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
    3627           0 :                 return;
    3628             :         }
    3629             : 
    3630           0 :         if (tevent_req_nterror(req, result)) {
    3631           0 :                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
    3632           0 :                 return;
    3633             :         }
    3634             : 
    3635           0 :         tevent_req_done(req);
    3636             : }
    3637             : 
    3638           0 : NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
    3639             :                         TALLOC_CTX *mem_ctx,
    3640             :                         struct lsa_ForestTrustInformation **forest_trust_info)
    3641             : {
    3642           0 :         struct netlogon_creds_cli_GetForestTrustInformation_state *state =
    3643           0 :                 tevent_req_data(req,
    3644             :                 struct netlogon_creds_cli_GetForestTrustInformation_state);
    3645             :         NTSTATUS status;
    3646             : 
    3647           0 :         if (tevent_req_is_nterror(req, &status)) {
    3648           0 :                 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
    3649           0 :                 tevent_req_received(req);
    3650           0 :                 return status;
    3651             :         }
    3652             : 
    3653           0 :         *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
    3654             : 
    3655           0 :         tevent_req_received(req);
    3656           0 :         return NT_STATUS_OK;
    3657             : }
    3658             : 
    3659           0 : NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
    3660             :                         struct netlogon_creds_cli_context *context,
    3661             :                         struct dcerpc_binding_handle *b,
    3662             :                         TALLOC_CTX *mem_ctx,
    3663             :                         struct lsa_ForestTrustInformation **forest_trust_info)
    3664             : {
    3665           0 :         TALLOC_CTX *frame = talloc_stackframe();
    3666             :         struct tevent_context *ev;
    3667             :         struct tevent_req *req;
    3668           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    3669             : 
    3670           0 :         ev = samba_tevent_context_init(frame);
    3671           0 :         if (ev == NULL) {
    3672           0 :                 goto fail;
    3673             :         }
    3674           0 :         req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
    3675           0 :         if (req == NULL) {
    3676           0 :                 goto fail;
    3677             :         }
    3678           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    3679           0 :                 goto fail;
    3680             :         }
    3681           0 :         status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
    3682             :                                                         mem_ctx,
    3683             :                                                         forest_trust_info);
    3684           0 :  fail:
    3685           0 :         TALLOC_FREE(frame);
    3686           0 :         return status;
    3687             : }
    3688             : struct netlogon_creds_cli_SendToSam_state {
    3689             :         struct tevent_context *ev;
    3690             :         struct netlogon_creds_cli_context *context;
    3691             :         struct dcerpc_binding_handle *binding_handle;
    3692             : 
    3693             :         char *srv_name_slash;
    3694             :         enum dcerpc_AuthType auth_type;
    3695             :         enum dcerpc_AuthLevel auth_level;
    3696             : 
    3697             :         DATA_BLOB opaque;
    3698             : 
    3699             :         struct netlogon_creds_CredentialState *creds;
    3700             :         struct netlogon_creds_CredentialState tmp_creds;
    3701             :         struct netr_Authenticator req_auth;
    3702             :         struct netr_Authenticator rep_auth;
    3703             : };
    3704             : 
    3705             : static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
    3706             :                                                                  NTSTATUS status);
    3707             : static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
    3708             : 
    3709           0 : struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
    3710             :                                                      struct tevent_context *ev,
    3711             :                                                      struct netlogon_creds_cli_context *context,
    3712             :                                                      struct dcerpc_binding_handle *b,
    3713             :                                                      struct netr_SendToSamBase *message)
    3714             : {
    3715             :         struct tevent_req *req;
    3716             :         struct netlogon_creds_cli_SendToSam_state *state;
    3717             :         struct tevent_req *subreq;
    3718             :         enum ndr_err_code ndr_err;
    3719             : 
    3720           0 :         req = tevent_req_create(mem_ctx, &state,
    3721             :                                 struct netlogon_creds_cli_SendToSam_state);
    3722           0 :         if (req == NULL) {
    3723           0 :                 return NULL;
    3724             :         }
    3725             : 
    3726           0 :         state->ev = ev;
    3727           0 :         state->context = context;
    3728           0 :         state->binding_handle = b;
    3729             : 
    3730           0 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    3731             :                                                 context->server.computer);
    3732           0 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    3733           0 :                 return tevent_req_post(req, ev);
    3734             :         }
    3735             : 
    3736           0 :         ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
    3737             :                                        (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
    3738           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    3739           0 :                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
    3740           0 :                 tevent_req_nterror(req, status);
    3741           0 :                 return tevent_req_post(req, ev);
    3742             :         }
    3743             : 
    3744           0 :         dcerpc_binding_handle_auth_info(state->binding_handle,
    3745           0 :                                         &state->auth_type,
    3746           0 :                                         &state->auth_level);
    3747             : 
    3748           0 :         subreq = netlogon_creds_cli_lock_send(state, state->ev,
    3749           0 :                                               state->context);
    3750           0 :         if (tevent_req_nomem(subreq, req)) {
    3751           0 :                 return tevent_req_post(req, ev);
    3752             :         }
    3753             : 
    3754           0 :         tevent_req_set_callback(subreq,
    3755             :                                 netlogon_creds_cli_SendToSam_locked,
    3756             :                                 req);
    3757             : 
    3758           0 :         return req;
    3759             : }
    3760             : 
    3761           0 : static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
    3762             :                                                          NTSTATUS status)
    3763             : {
    3764           0 :         struct netlogon_creds_cli_SendToSam_state *state =
    3765           0 :                 tevent_req_data(req,
    3766             :                 struct netlogon_creds_cli_SendToSam_state);
    3767             : 
    3768           0 :         if (state->creds == NULL) {
    3769           0 :                 return;
    3770             :         }
    3771             : 
    3772           0 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
    3773           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
    3774           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
    3775           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
    3776           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
    3777           0 :                 TALLOC_FREE(state->creds);
    3778           0 :                 return;
    3779             :         }
    3780             : 
    3781           0 :         netlogon_creds_cli_delete(state->context, state->creds);
    3782           0 :         TALLOC_FREE(state->creds);
    3783             : }
    3784             : 
    3785             : static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
    3786             : 
    3787           0 : static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
    3788             : {
    3789           0 :         struct tevent_req *req =
    3790           0 :                 tevent_req_callback_data(subreq,
    3791             :                 struct tevent_req);
    3792           0 :         struct netlogon_creds_cli_SendToSam_state *state =
    3793           0 :                 tevent_req_data(req,
    3794             :                 struct netlogon_creds_cli_SendToSam_state);
    3795             :         NTSTATUS status;
    3796             : 
    3797           0 :         status = netlogon_creds_cli_lock_recv(subreq, state,
    3798             :                                               &state->creds);
    3799           0 :         TALLOC_FREE(subreq);
    3800           0 :         if (tevent_req_nterror(req, status)) {
    3801           0 :                 return;
    3802             :         }
    3803             : 
    3804           0 :         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
    3805           0 :                 switch (state->auth_level) {
    3806           0 :                 case DCERPC_AUTH_LEVEL_INTEGRITY:
    3807             :                 case DCERPC_AUTH_LEVEL_PRIVACY:
    3808           0 :                         break;
    3809           0 :                 default:
    3810           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    3811           0 :                         return;
    3812             :                 }
    3813             :         } else {
    3814           0 :                 uint32_t tmp = state->creds->negotiate_flags;
    3815             : 
    3816           0 :                 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
    3817             :                         /*
    3818             :                          * if DCERPC_AUTH_TYPE_SCHANNEL is supported
    3819             :                          * it should be used, which means
    3820             :                          * we had a chance to verify no downgrade
    3821             :                          * happened.
    3822             :                          *
    3823             :                          * This relies on netlogon_creds_cli_check*
    3824             :                          * being called before, as first request after
    3825             :                          * the DCERPC bind.
    3826             :                          */
    3827           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    3828           0 :                         return;
    3829             :                 }
    3830             :         }
    3831             : 
    3832             :         /*
    3833             :          * we defer all callbacks in order to cleanup
    3834             :          * the database record.
    3835             :          */
    3836           0 :         tevent_req_defer_callback(req, state->ev);
    3837             : 
    3838           0 :         state->tmp_creds = *state->creds;
    3839           0 :         status = netlogon_creds_client_authenticator(&state->tmp_creds,
    3840             :                                                      &state->req_auth);
    3841           0 :         if (tevent_req_nterror(req, status)) {
    3842           0 :                 return;
    3843             :         }
    3844           0 :         ZERO_STRUCT(state->rep_auth);
    3845             : 
    3846           0 :         if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
    3847           0 :                 status = netlogon_creds_aes_encrypt(&state->tmp_creds,
    3848             :                                                     state->opaque.data,
    3849             :                                                     state->opaque.length);
    3850           0 :                 if (tevent_req_nterror(req, status)) {
    3851           0 :                         netlogon_creds_cli_SendToSam_cleanup(req, status);
    3852           0 :                         return;
    3853             :                 }
    3854             :         } else {
    3855           0 :                 status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
    3856             :                                                       state->opaque.data,
    3857             :                                                       state->opaque.length);
    3858           0 :                 if (tevent_req_nterror(req, status)) {
    3859           0 :                         netlogon_creds_cli_SendToSam_cleanup(req, status);
    3860           0 :                         return;
    3861             :                 }
    3862             :         }
    3863             : 
    3864           0 :         subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
    3865             :                                                      state->binding_handle,
    3866           0 :                                                      state->srv_name_slash,
    3867             :                                                      state->tmp_creds.computer_name,
    3868             :                                                      &state->req_auth,
    3869             :                                                      &state->rep_auth,
    3870             :                                                      state->opaque.data,
    3871           0 :                                                      state->opaque.length);
    3872           0 :         if (tevent_req_nomem(subreq, req)) {
    3873           0 :                 status = NT_STATUS_NO_MEMORY;
    3874           0 :                 netlogon_creds_cli_SendToSam_cleanup(req, status);
    3875           0 :                 return;
    3876             :         }
    3877             : 
    3878           0 :         tevent_req_set_callback(subreq,
    3879             :                                 netlogon_creds_cli_SendToSam_done,
    3880             :                                 req);
    3881             : }
    3882             : 
    3883           0 : static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
    3884             : {
    3885           0 :         struct tevent_req *req =
    3886           0 :                 tevent_req_callback_data(subreq,
    3887             :                 struct tevent_req);
    3888           0 :         struct netlogon_creds_cli_SendToSam_state *state =
    3889           0 :                 tevent_req_data(req,
    3890             :                 struct netlogon_creds_cli_SendToSam_state);
    3891             :         NTSTATUS status;
    3892             :         NTSTATUS result;
    3893             :         bool ok;
    3894             : 
    3895           0 :         status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
    3896           0 :         TALLOC_FREE(subreq);
    3897           0 :         if (tevent_req_nterror(req, status)) {
    3898           0 :                 netlogon_creds_cli_SendToSam_cleanup(req, status);
    3899           0 :                 return;
    3900             :         }
    3901             : 
    3902           0 :         ok = netlogon_creds_client_check(&state->tmp_creds,
    3903           0 :                                          &state->rep_auth.cred);
    3904           0 :         if (!ok) {
    3905           0 :                 status = NT_STATUS_ACCESS_DENIED;
    3906           0 :                 tevent_req_nterror(req, status);
    3907           0 :                 netlogon_creds_cli_SendToSam_cleanup(req, status);
    3908           0 :                 return;
    3909             :         }
    3910             : 
    3911           0 :         *state->creds = state->tmp_creds;
    3912           0 :         status = netlogon_creds_cli_store(state->context,
    3913             :                                           state->creds);
    3914           0 :         TALLOC_FREE(state->creds);
    3915             : 
    3916           0 :         if (tevent_req_nterror(req, status)) {
    3917           0 :                 netlogon_creds_cli_SendToSam_cleanup(req, status);
    3918           0 :                 return;
    3919             :         }
    3920             : 
    3921             :         /*
    3922             :          * Creds must be stored before we send back application errors
    3923             :          * e.g. NT_STATUS_NOT_IMPLEMENTED
    3924             :          */
    3925           0 :         if (tevent_req_nterror(req, result)) {
    3926           0 :                 netlogon_creds_cli_SendToSam_cleanup(req, result);
    3927           0 :                 return;
    3928             :         }
    3929             : 
    3930           0 :         tevent_req_done(req);
    3931             : }
    3932             : 
    3933           0 : NTSTATUS netlogon_creds_cli_SendToSam_recv(struct tevent_req *req)
    3934             : {
    3935             :         NTSTATUS status;
    3936             : 
    3937           0 :         if (tevent_req_is_nterror(req, &status)) {
    3938           0 :                 netlogon_creds_cli_SendToSam_cleanup(req, status);
    3939           0 :                 tevent_req_received(req);
    3940           0 :                 return status;
    3941             :         }
    3942             : 
    3943           0 :         tevent_req_received(req);
    3944           0 :         return NT_STATUS_OK;
    3945             : }
    3946             : 
    3947           0 : NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
    3948             :                                       struct dcerpc_binding_handle *b,
    3949             :                                       struct netr_SendToSamBase *message)
    3950             : {
    3951           0 :         TALLOC_CTX *frame = talloc_stackframe();
    3952             :         struct tevent_context *ev;
    3953             :         struct tevent_req *req;
    3954           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    3955             : 
    3956           0 :         ev = samba_tevent_context_init(frame);
    3957           0 :         if (ev == NULL) {
    3958           0 :                 goto fail;
    3959             :         }
    3960           0 :         req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
    3961           0 :         if (req == NULL) {
    3962           0 :                 goto fail;
    3963             :         }
    3964           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    3965           0 :                 goto fail;
    3966             :         }
    3967           0 :         status = netlogon_creds_cli_SendToSam_recv(req);
    3968           0 :  fail:
    3969           0 :         TALLOC_FREE(frame);
    3970           0 :         return status;
    3971             : }
    3972             : 
    3973             : struct netlogon_creds_cli_LogonGetDomainInfo_state {
    3974             :         struct tevent_context *ev;
    3975             :         struct netlogon_creds_cli_context *context;
    3976             :         struct dcerpc_binding_handle *binding_handle;
    3977             : 
    3978             :         char *srv_name_slash;
    3979             :         enum dcerpc_AuthType auth_type;
    3980             :         enum dcerpc_AuthLevel auth_level;
    3981             : 
    3982             :         uint32_t level;
    3983             :         union netr_WorkstationInfo *query;
    3984             :         union netr_DomainInfo *info;
    3985             : 
    3986             :         struct netlogon_creds_CredentialState *creds;
    3987             :         struct netlogon_creds_CredentialState tmp_creds;
    3988             :         struct netr_Authenticator req_auth;
    3989             :         struct netr_Authenticator rep_auth;
    3990             : };
    3991             : 
    3992             : static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
    3993             :                                                      NTSTATUS status);
    3994             : static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq);
    3995             : 
    3996           0 : struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
    3997             :                                         struct tevent_context *ev,
    3998             :                                         struct netlogon_creds_cli_context *context,
    3999             :                                         struct dcerpc_binding_handle *b,
    4000             :                                         uint32_t level,
    4001             :                                         union netr_WorkstationInfo *query)
    4002             : {
    4003             :         struct tevent_req *req;
    4004             :         struct netlogon_creds_cli_LogonGetDomainInfo_state *state;
    4005             :         struct tevent_req *subreq;
    4006             : 
    4007           0 :         req = tevent_req_create(mem_ctx, &state,
    4008             :                                 struct netlogon_creds_cli_LogonGetDomainInfo_state);
    4009           0 :         if (req == NULL) {
    4010           0 :                 return NULL;
    4011             :         }
    4012             : 
    4013           0 :         state->ev = ev;
    4014           0 :         state->context = context;
    4015           0 :         state->binding_handle = b;
    4016             : 
    4017           0 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    4018             :                                                 context->server.computer);
    4019           0 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    4020           0 :                 return tevent_req_post(req, ev);
    4021             :         }
    4022             : 
    4023           0 :         state->level = level;
    4024           0 :         state->query = query;
    4025           0 :         state->info = talloc_zero(state, union netr_DomainInfo);
    4026           0 :         if (tevent_req_nomem(state->info, req)) {
    4027           0 :                 return tevent_req_post(req, ev);
    4028             :         }
    4029             : 
    4030           0 :         dcerpc_binding_handle_auth_info(state->binding_handle,
    4031           0 :                                         &state->auth_type,
    4032           0 :                                         &state->auth_level);
    4033             : 
    4034           0 :         subreq = netlogon_creds_cli_lock_send(state, state->ev,
    4035           0 :                                               state->context);
    4036           0 :         if (tevent_req_nomem(subreq, req)) {
    4037           0 :                 return tevent_req_post(req, ev);
    4038             :         }
    4039             : 
    4040           0 :         tevent_req_set_callback(subreq,
    4041             :                                 netlogon_creds_cli_LogonGetDomainInfo_locked,
    4042             :                                 req);
    4043             : 
    4044           0 :         return req;
    4045             : }
    4046             : 
    4047           0 : static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
    4048             :                                                          NTSTATUS status)
    4049             : {
    4050           0 :         struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
    4051           0 :                 tevent_req_data(req,
    4052             :                 struct netlogon_creds_cli_LogonGetDomainInfo_state);
    4053             : 
    4054           0 :         if (state->creds == NULL) {
    4055           0 :                 return;
    4056             :         }
    4057             : 
    4058           0 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
    4059           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
    4060           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
    4061           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
    4062           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
    4063           0 :                 TALLOC_FREE(state->creds);
    4064           0 :                 return;
    4065             :         }
    4066             : 
    4067           0 :         netlogon_creds_cli_delete(state->context, state->creds);
    4068             : }
    4069             : 
    4070             : static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq);
    4071             : 
    4072           0 : static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq)
    4073             : {
    4074           0 :         struct tevent_req *req =
    4075           0 :                 tevent_req_callback_data(subreq,
    4076             :                 struct tevent_req);
    4077           0 :         struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
    4078           0 :                 tevent_req_data(req,
    4079             :                 struct netlogon_creds_cli_LogonGetDomainInfo_state);
    4080             :         NTSTATUS status;
    4081             : 
    4082           0 :         status = netlogon_creds_cli_lock_recv(subreq, state,
    4083             :                                               &state->creds);
    4084           0 :         TALLOC_FREE(subreq);
    4085           0 :         if (tevent_req_nterror(req, status)) {
    4086           0 :                 return;
    4087             :         }
    4088             : 
    4089           0 :         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
    4090           0 :                 switch (state->auth_level) {
    4091           0 :                 case DCERPC_AUTH_LEVEL_INTEGRITY:
    4092             :                 case DCERPC_AUTH_LEVEL_PRIVACY:
    4093           0 :                         break;
    4094           0 :                 default:
    4095           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    4096           0 :                         return;
    4097             :                 }
    4098             :         } else {
    4099           0 :                 uint32_t tmp = state->creds->negotiate_flags;
    4100             : 
    4101           0 :                 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
    4102             :                         /*
    4103             :                          * if DCERPC_AUTH_TYPE_SCHANNEL is supported
    4104             :                          * it should be used, which means
    4105             :                          * we had a chance to verify no downgrade
    4106             :                          * happened.
    4107             :                          *
    4108             :                          * This relies on netlogon_creds_cli_check*
    4109             :                          * being called before, as first request after
    4110             :                          * the DCERPC bind.
    4111             :                          */
    4112           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    4113           0 :                         return;
    4114             :                 }
    4115             :         }
    4116             : 
    4117             :         /*
    4118             :          * we defer all callbacks in order to cleanup
    4119             :          * the database record.
    4120             :          */
    4121           0 :         tevent_req_defer_callback(req, state->ev);
    4122             : 
    4123           0 :         state->tmp_creds = *state->creds;
    4124           0 :         status = netlogon_creds_client_authenticator(&state->tmp_creds,
    4125             :                                                      &state->req_auth);
    4126           0 :         if (tevent_req_nterror(req, status)) {
    4127           0 :                 return;
    4128             :         }
    4129           0 :         ZERO_STRUCT(state->rep_auth);
    4130             : 
    4131           0 :         subreq = dcerpc_netr_LogonGetDomainInfo_send(state, state->ev,
    4132             :                                                 state->binding_handle,
    4133           0 :                                                 state->srv_name_slash,
    4134             :                                                 state->tmp_creds.computer_name,
    4135             :                                                 &state->req_auth,
    4136             :                                                 &state->rep_auth,
    4137             :                                                 state->level,
    4138             :                                                 state->query,
    4139             :                                                 state->info);
    4140           0 :         if (tevent_req_nomem(subreq, req)) {
    4141           0 :                 status = NT_STATUS_NO_MEMORY;
    4142           0 :                 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
    4143           0 :                 return;
    4144             :         }
    4145             : 
    4146           0 :         tevent_req_set_callback(subreq,
    4147             :                                 netlogon_creds_cli_LogonGetDomainInfo_done,
    4148             :                                 req);
    4149             : }
    4150             : 
    4151           0 : static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq)
    4152             : {
    4153           0 :         struct tevent_req *req =
    4154           0 :                 tevent_req_callback_data(subreq,
    4155             :                 struct tevent_req);
    4156           0 :         struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
    4157           0 :                 tevent_req_data(req,
    4158             :                 struct netlogon_creds_cli_LogonGetDomainInfo_state);
    4159             :         NTSTATUS status;
    4160             :         NTSTATUS result;
    4161             :         bool ok;
    4162             : 
    4163             :         /*
    4164             :          * We use state->dns_names as the memory context, as this is
    4165             :          * the only in/out variable and it has been overwritten by the
    4166             :          * out parameter from the server.
    4167             :          *
    4168             :          * We need to preserve the return value until the caller can use it.
    4169             :          */
    4170           0 :         status = dcerpc_netr_LogonGetDomainInfo_recv(subreq, state->info, &result);
    4171           0 :         TALLOC_FREE(subreq);
    4172           0 :         if (tevent_req_nterror(req, status)) {
    4173           0 :                 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
    4174           0 :                 return;
    4175             :         }
    4176             : 
    4177           0 :         ok = netlogon_creds_client_check(&state->tmp_creds,
    4178           0 :                                          &state->rep_auth.cred);
    4179           0 :         if (!ok) {
    4180           0 :                 status = NT_STATUS_ACCESS_DENIED;
    4181           0 :                 tevent_req_nterror(req, status);
    4182           0 :                 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
    4183           0 :                 return;
    4184             :         }
    4185             : 
    4186           0 :         if (tevent_req_nterror(req, result)) {
    4187           0 :                 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result);
    4188           0 :                 return;
    4189             :         }
    4190             : 
    4191           0 :         *state->creds = state->tmp_creds;
    4192           0 :         status = netlogon_creds_cli_store(state->context,
    4193             :                                           state->creds);
    4194           0 :         if (tevent_req_nterror(req, status)) {
    4195           0 :                 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
    4196           0 :                 return;
    4197             :         }
    4198             : 
    4199           0 :         tevent_req_done(req);
    4200             : }
    4201             : 
    4202           0 : NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
    4203             :                         TALLOC_CTX *mem_ctx,
    4204             :                         union netr_DomainInfo **info)
    4205             : {
    4206           0 :         struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
    4207           0 :                 tevent_req_data(req,
    4208             :                 struct netlogon_creds_cli_LogonGetDomainInfo_state);
    4209             :         NTSTATUS status;
    4210             : 
    4211           0 :         if (tevent_req_is_nterror(req, &status)) {
    4212           0 :                 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
    4213           0 :                 tevent_req_received(req);
    4214           0 :                 return status;
    4215             :         }
    4216             : 
    4217           0 :         *info = talloc_move(mem_ctx, &state->info);
    4218             : 
    4219           0 :         tevent_req_received(req);
    4220           0 :         return NT_STATUS_OK;
    4221             : }
    4222             : 
    4223           0 : NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
    4224             :                         struct netlogon_creds_cli_context *context,
    4225             :                         struct dcerpc_binding_handle *b,
    4226             :                         TALLOC_CTX *mem_ctx,
    4227             :                         uint32_t level,
    4228             :                         union netr_WorkstationInfo *query,
    4229             :                         union netr_DomainInfo **info)
    4230             : {
    4231           0 :         TALLOC_CTX *frame = talloc_stackframe();
    4232             :         struct tevent_context *ev;
    4233             :         struct tevent_req *req;
    4234           0 :         NTSTATUS status = NT_STATUS_OK;
    4235             : 
    4236           0 :         ev = samba_tevent_context_init(frame);
    4237           0 :         if (ev == NULL) {
    4238           0 :                 goto fail;
    4239             :         }
    4240           0 :         req = netlogon_creds_cli_LogonGetDomainInfo_send(frame, ev, context, b,
    4241             :                                                          level, query);
    4242           0 :         if (req == NULL) {
    4243           0 :                 goto fail;
    4244             :         }
    4245           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    4246           0 :                 goto fail;
    4247             :         }
    4248           0 :         status = netlogon_creds_cli_LogonGetDomainInfo_recv(req,
    4249             :                                                             mem_ctx,
    4250             :                                                             info);
    4251           0 :  fail:
    4252           0 :         TALLOC_FREE(frame);
    4253           0 :         return status;
    4254             : }

Generated by: LCOV version 1.13