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

Generated by: LCOV version 1.14