LCOV - code coverage report
Current view: top level - libcli/auth - netlogon_creds_cli.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 721 2032 35.5 %
Date: 2024-05-31 13:13:24 Functions: 45 82 54.9 %

          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          26 : static int netlogon_creds_cli_locked_state_destructor(
      83             :                 struct netlogon_creds_cli_locked_state *state)
      84             : {
      85          26 :         struct netlogon_creds_cli_context *context = state->context;
      86             : 
      87          26 :         if (context == NULL) {
      88           0 :                 return 0;
      89             :         }
      90             : 
      91          26 :         if (context->db.locked_state == state) {
      92          26 :                 context->db.locked_state = NULL;
      93             :         }
      94             : 
      95          26 :         if (state->is_glocked) {
      96          26 :                 g_lock_unlock(context->db.g_ctx,
      97             :                               string_term_tdb_data(context->db.key_name));
      98             :         }
      99             : 
     100          26 :         return 0;
     101             : }
     102             : 
     103         132 : 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         132 :         struct netlogon_creds_cli_context *context = NULL;
     117         132 :         char *_key_name = NULL;
     118           0 :         size_t server_netbios_name_len;
     119         132 :         char *p = NULL;
     120             : 
     121         132 :         *_context = NULL;
     122             : 
     123         132 :         context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
     124         132 :         if (context == NULL) {
     125           0 :                 return NT_STATUS_NO_MEMORY;
     126             :         }
     127             : 
     128         132 :         context->client.computer = talloc_strdup(context, client_computer);
     129         132 :         if (context->client.computer == NULL) {
     130           0 :                 TALLOC_FREE(context);
     131           0 :                 return NT_STATUS_NO_MEMORY;
     132             :         }
     133             : 
     134         132 :         context->client.account = talloc_strdup(context, client_account);
     135         132 :         if (context->client.account == NULL) {
     136           0 :                 TALLOC_FREE(context);
     137           0 :                 return NT_STATUS_NO_MEMORY;
     138             :         }
     139             : 
     140         132 :         context->client.proposed_flags = proposed_flags;
     141         132 :         context->client.required_flags = required_flags;
     142         132 :         context->client.type = type;
     143         132 :         context->client.auth_level = auth_level;
     144             : 
     145         132 :         context->server.computer = talloc_strdup(context, server_computer);
     146         132 :         if (context->server.computer == NULL) {
     147           0 :                 TALLOC_FREE(context);
     148           0 :                 return NT_STATUS_NO_MEMORY;
     149             :         }
     150             : 
     151         132 :         context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
     152         132 :         if (context->server.netbios_domain == NULL) {
     153           0 :                 TALLOC_FREE(context);
     154           0 :                 return NT_STATUS_NO_MEMORY;
     155             :         }
     156             : 
     157         132 :         context->server.dns_domain = talloc_strdup(context, server_dns_domain);
     158         132 :         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         132 :         p = strchr(server_computer, '.');
     173         132 :         if (p != NULL) {
     174          52 :                 server_netbios_name_len = p-server_computer;
     175             :         } else {
     176          80 :                 server_netbios_name_len = strlen(server_computer);
     177             :         }
     178             : 
     179         132 :         _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         132 :         if (_key_name == NULL) {
     186           0 :                 TALLOC_FREE(context);
     187           0 :                 return NT_STATUS_NO_MEMORY;
     188             :         }
     189             : 
     190         132 :         context->db.key_name = talloc_strdup_upper(context, _key_name);
     191         132 :         TALLOC_FREE(_key_name);
     192         132 :         if (context->db.key_name == NULL) {
     193           0 :                 TALLOC_FREE(context);
     194           0 :                 return NT_STATUS_NO_MEMORY;
     195             :         }
     196             : 
     197         132 :         context->db.key_data = string_term_tdb_data(context->db.key_name);
     198             : 
     199         132 :         *_context = context;
     200         132 :         return NT_STATUS_OK;
     201             : }
     202             : 
     203             : static struct db_context *netlogon_creds_cli_global_db;
     204             : 
     205         168 : NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx,
     206             :                                           struct db_context **db)
     207             : {
     208         168 :         netlogon_creds_cli_warn_options(lp_ctx);
     209             : 
     210         168 :         if (netlogon_creds_cli_global_db != NULL) {
     211           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     212             :         }
     213             : 
     214         168 :         netlogon_creds_cli_global_db = talloc_move(NULL, db);
     215         168 :         return NT_STATUS_OK;
     216             : }
     217             : 
     218         132 : NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
     219             : {
     220           0 :         char *fname;
     221           0 :         struct db_context *global_db;
     222           0 :         int hash_size, tdb_flags;
     223             : 
     224         132 :         netlogon_creds_cli_warn_options(lp_ctx);
     225             : 
     226         132 :         if (netlogon_creds_cli_global_db != NULL) {
     227         132 :                 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       33708 : void netlogon_creds_cli_close_global_db(void)
     262             : {
     263       33708 :         TALLOC_FREE(netlogon_creds_cli_global_db);
     264       33708 : }
     265             : 
     266         538 : void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx)
     267             : {
     268         538 :         bool global_reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
     269         538 :         bool global_require_strong_key = lpcfg_require_strong_key(lp_ctx);
     270         538 :         int global_client_schannel = lpcfg_client_schannel(lp_ctx);
     271         538 :         bool global_seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
     272         538 :         int global_kerberos_enctypes = lpcfg_kerberos_encryption_types(lp_ctx);
     273           0 :         static bool warned_global_reject_md5_servers = false;
     274           0 :         static bool warned_global_require_strong_key = false;
     275           0 :         static bool warned_global_client_schannel = false;
     276           0 :         static bool warned_global_seal_secure_channel = false;
     277           0 :         static bool warned_global_kerberos_encryption_types = false;
     278           0 :         static int warned_global_pid = 0;
     279         538 :         int current_pid = tevent_cached_getpid();
     280             : 
     281         538 :         if (warned_global_pid != current_pid) {
     282         269 :                 warned_global_reject_md5_servers = false;
     283         269 :                 warned_global_require_strong_key = false;
     284         269 :                 warned_global_client_schannel = false;
     285         269 :                 warned_global_seal_secure_channel = false;
     286         269 :                 warned_global_kerberos_encryption_types = false;
     287         269 :                 warned_global_pid = current_pid;
     288             :         }
     289             : 
     290         538 :         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         538 :         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         538 :         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         538 :         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         538 :         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         538 : }
     342             : 
     343         132 : 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         132 :         TALLOC_CTX *frame = talloc_stackframe();
     354           0 :         NTSTATUS status;
     355         132 :         struct netlogon_creds_cli_context *context = NULL;
     356           0 :         const char *client_computer;
     357           0 :         uint32_t proposed_flags;
     358         132 :         uint32_t required_flags = 0;
     359         132 :         bool reject_md5_servers = true;
     360         132 :         bool require_strong_key = true;
     361         132 :         int require_sign_or_seal = true;
     362         132 :         bool seal_secure_channel = true;
     363         132 :         enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
     364         132 :         bool neutralize_nt4_emulation = false;
     365             : 
     366         132 :         *_context = NULL;
     367             : 
     368         132 :         if (msg_ctx == NULL) {
     369           0 :                 TALLOC_FREE(frame);
     370           0 :                 return NT_STATUS_INVALID_PARAMETER_MIX;
     371             :         }
     372             : 
     373         132 :         client_computer = lpcfg_netbios_name(lp_ctx);
     374         132 :         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         132 :         reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
     384         132 :         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         132 :         require_strong_key = lpcfg_require_strong_key(lp_ctx);
     394         132 :         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         132 :         require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
     404         132 :         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         132 :         seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
     414         132 :         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         132 :         neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
     424         132 :         neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
     425             :                                                    "neutralize nt4 emulation",
     426             :                                                    server_netbios_domain,
     427             :                                                    neutralize_nt4_emulation);
     428             : 
     429         132 :         proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
     430         132 :         proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
     431             : 
     432         132 :         switch (type) {
     433          84 :         case SEC_CHAN_WKSTA:
     434          84 :                 if (lpcfg_security(lp_ctx) == SEC_ADS) {
     435             :                         /*
     436             :                          * AD domains should be secure
     437             :                          */
     438          62 :                         required_flags |= NETLOGON_NEG_PASSWORD_SET2;
     439          62 :                         require_sign_or_seal = true;
     440          62 :                         require_strong_key = true;
     441             :                 }
     442          84 :                 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          42 :         case SEC_CHAN_BDC:
     458          42 :                 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
     459          42 :                 require_sign_or_seal = true;
     460          42 :                 require_strong_key = true;
     461          42 :                 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         132 :         if (neutralize_nt4_emulation) {
     477           6 :                 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
     478             :         }
     479             : 
     480         132 :         if (require_sign_or_seal) {
     481         132 :                 required_flags |= NETLOGON_NEG_ARCFOUR;
     482         132 :                 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
     483             :         } else {
     484           0 :                 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
     485             :         }
     486             : 
     487         132 :         if (reject_md5_servers) {
     488         132 :                 required_flags |= NETLOGON_NEG_ARCFOUR;
     489         132 :                 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
     490         132 :                 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
     491         132 :                 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
     492             :         }
     493             : 
     494         132 :         if (require_strong_key) {
     495         132 :                 required_flags |= NETLOGON_NEG_ARCFOUR;
     496         132 :                 required_flags |= NETLOGON_NEG_STRONG_KEYS;
     497         132 :                 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         132 :         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         132 :         proposed_flags |= required_flags;
     512             : 
     513         132 :         if (seal_secure_channel) {
     514         132 :                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
     515             :         } else {
     516           0 :                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
     517             :         }
     518             : 
     519         132 :         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         132 :         if (!NT_STATUS_IS_OK(status)) {
     531           0 :                 TALLOC_FREE(frame);
     532           0 :                 return status;
     533             :         }
     534             : 
     535         132 :         context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
     536         132 :         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         132 :         status = netlogon_creds_cli_open_global_db(lp_ctx);
     543         132 :         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         132 :         context->db.ctx = netlogon_creds_cli_global_db;
     550         132 :         *_context = context;
     551         132 :         TALLOC_FREE(frame);
     552         132 :         return NT_STATUS_OK;
     553             : }
     554             : 
     555         107 : 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           0 :         struct cli_credentials *cli_creds;
     560           0 :         struct netlogon_creds_CredentialState *ncreds;
     561           0 :         NTSTATUS status;
     562             : 
     563         107 :         cli_creds = cli_credentials_init(mem_ctx);
     564         107 :         if (cli_creds == NULL) {
     565           0 :                 return NT_STATUS_NO_MEMORY;
     566             :         }
     567         107 :         cli_credentials_set_secure_channel_type(cli_creds,
     568             :                                                 context->client.type);
     569         107 :         cli_credentials_set_username(cli_creds, context->client.account,
     570             :                                      CRED_SPECIFIED);
     571         107 :         cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
     572             :                                    CRED_SPECIFIED);
     573         107 :         cli_credentials_set_realm(cli_creds, context->server.dns_domain,
     574             :                                   CRED_SPECIFIED);
     575             : 
     576         107 :         status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
     577         107 :         if (!NT_STATUS_IS_OK(status)) {
     578           0 :                 TALLOC_FREE(cli_creds);
     579           0 :                 return status;
     580             :         }
     581         107 :         cli_credentials_set_netlogon_creds(cli_creds, ncreds);
     582             : 
     583         107 :         *pcli_creds = cli_creds;
     584         107 :         return NT_STATUS_OK;
     585             : }
     586             : 
     587           6 : char *netlogon_creds_cli_debug_string(
     588             :                 const struct netlogon_creds_cli_context *context,
     589             :                 TALLOC_CTX *mem_ctx)
     590             : {
     591          12 :         return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
     592           6 :                                context->db.key_name);
     593             : }
     594             : 
     595         107 : enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
     596             :                 struct netlogon_creds_cli_context *context)
     597             : {
     598         107 :         return context->client.auth_level;
     599             : }
     600             : 
     601         602 : static bool netlogon_creds_cli_downgraded(uint32_t negotiated_flags,
     602             :                                           uint32_t proposed_flags,
     603             :                                           uint32_t required_flags)
     604             : {
     605         602 :         uint32_t req_flags = required_flags;
     606           0 :         uint32_t tmp_flags;
     607             : 
     608         602 :         req_flags = required_flags;
     609         602 :         if ((negotiated_flags & NETLOGON_NEG_SUPPORTS_AES) &&
     610         602 :             (proposed_flags & NETLOGON_NEG_SUPPORTS_AES))
     611             :         {
     612         602 :                 req_flags &= ~NETLOGON_NEG_ARCFOUR|NETLOGON_NEG_STRONG_KEYS;
     613             :         }
     614             : 
     615         602 :         tmp_flags = negotiated_flags;
     616         602 :         tmp_flags &= req_flags;
     617         602 :         if (tmp_flags != req_flags) {
     618           0 :                 return true;
     619             :         }
     620             : 
     621         602 :         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         484 : static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
     633             :                                             void *private_data)
     634             : {
     635         484 :         struct netlogon_creds_cli_fetch_state *state =
     636             :                 (struct netlogon_creds_cli_fetch_state *)private_data;
     637           0 :         enum ndr_err_code ndr_err;
     638           0 :         DATA_BLOB blob;
     639           0 :         bool downgraded;
     640             : 
     641         484 :         state->creds = talloc_zero(state->mem_ctx,
     642             :                                    struct netlogon_creds_CredentialState);
     643         484 :         if (state->creds == NULL) {
     644           0 :                 state->status = NT_STATUS_NO_MEMORY;
     645           0 :                 return;
     646             :         }
     647             : 
     648         484 :         blob.data = data.dptr;
     649         484 :         blob.length = data.dsize;
     650             : 
     651         484 :         ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
     652             :                 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
     653         484 :         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         484 :         if (DEBUGLEVEL >= 10) {
     660           0 :                 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
     661             :         }
     662             : 
     663         484 :         downgraded = netlogon_creds_cli_downgraded(
     664         484 :                         state->creds->negotiate_flags,
     665             :                         state->proposed_flags,
     666             :                         state->required_flags);
     667         484 :         if (downgraded) {
     668           0 :                 TALLOC_FREE(state->creds);
     669           0 :                 state->status = NT_STATUS_DOWNGRADE_DETECTED;
     670           0 :                 return;
     671             :         }
     672             : 
     673         484 :         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         438 : NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
     681             :                                 TALLOC_CTX *mem_ctx,
     682             :                                 struct netlogon_creds_CredentialState **_creds)
     683             : {
     684           0 :         NTSTATUS status;
     685           0 :         struct netlogon_creds_CredentialState *creds;
     686             : 
     687         438 :         *_creds = NULL;
     688             : 
     689         438 :         status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
     690         438 :         if (!NT_STATUS_IS_OK(status)) {
     691          83 :                 return status;
     692             :         }
     693             : 
     694             :         /*
     695             :          * mark it as invalid for step operations.
     696             :          */
     697         355 :         creds->sequence = 0;
     698         355 :         creds->seed = (struct netr_Credential) {{0}};
     699         355 :         creds->client = (struct netr_Credential) {{0}};
     700         355 :         creds->server = (struct netr_Credential) {{0}};
     701             : 
     702         355 :         *_creds = creds;
     703         355 :         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           0 :         struct netlogon_creds_CredentialState *creds2;
     711           0 :         DATA_BLOB blob1;
     712           0 :         DATA_BLOB blob2;
     713           0 :         NTSTATUS status;
     714           0 :         enum ndr_err_code ndr_err;
     715           0 :         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         129 : static NTSTATUS netlogon_creds_cli_store_internal(
     745             :         struct netlogon_creds_cli_context *context,
     746             :         struct netlogon_creds_CredentialState *creds)
     747             : {
     748           0 :         NTSTATUS status;
     749           0 :         enum ndr_err_code ndr_err;
     750           0 :         DATA_BLOB blob;
     751           0 :         TDB_DATA data;
     752             : 
     753         129 :         if (DEBUGLEVEL >= 10) {
     754           0 :                 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
     755             :         }
     756             : 
     757         129 :         ndr_err = ndr_push_struct_blob(&blob, creds, creds,
     758             :                 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
     759         129 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     760           0 :                 status = ndr_map_error2ntstatus(ndr_err);
     761           0 :                 return status;
     762             :         }
     763             : 
     764         129 :         data.dptr = blob.data;
     765         129 :         data.dsize = blob.length;
     766             : 
     767         129 :         status = dbwrap_store(context->db.ctx,
     768             :                               context->db.key_data,
     769             :                               data, TDB_REPLACE);
     770         129 :         TALLOC_FREE(data.dptr);
     771         129 :         if (!NT_STATUS_IS_OK(status)) {
     772           0 :                 return status;
     773             :         }
     774             : 
     775         129 :         return NT_STATUS_OK;
     776             : }
     777             : 
     778          26 : NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
     779             :                                   struct netlogon_creds_CredentialState *creds)
     780             : {
     781           0 :         NTSTATUS status;
     782             : 
     783          26 :         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          26 :         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          26 :         status = netlogon_creds_cli_store_internal(context, creds);
     798          26 :         return status;
     799             : }
     800             : 
     801           0 : static NTSTATUS netlogon_creds_cli_delete_internal(
     802             :         struct netlogon_creds_cli_context *context)
     803             : {
     804           0 :         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           0 :         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           0 :         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          26 : 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           0 :         struct tevent_req *req;
     857           0 :         struct netlogon_creds_cli_lock_state *state;
     858           0 :         struct netlogon_creds_cli_locked_state *locked_state;
     859           0 :         struct tevent_req *subreq;
     860             : 
     861          26 :         req = tevent_req_create(mem_ctx, &state,
     862             :                                 struct netlogon_creds_cli_lock_state);
     863          26 :         if (req == NULL) {
     864           0 :                 return NULL;
     865             :         }
     866             : 
     867          26 :         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          26 :         locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
     873          26 :         if (tevent_req_nomem(locked_state, req)) {
     874           0 :                 return tevent_req_post(req, ev);
     875             :         }
     876          26 :         talloc_set_destructor(locked_state,
     877             :                               netlogon_creds_cli_locked_state_destructor);
     878          26 :         locked_state->context = context;
     879             : 
     880          26 :         context->db.locked_state = locked_state;
     881          26 :         state->locked_state = locked_state;
     882             : 
     883          26 :         if (context->db.g_ctx == NULL) {
     884           0 :                 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          26 :         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          26 :         if (tevent_req_nomem(subreq, req)) {
     901           0 :                 return tevent_req_post(req, ev);
     902             :         }
     903          26 :         tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
     904             : 
     905          26 :         return req;
     906             : }
     907             : 
     908          26 : static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
     909             : {
     910           0 :         struct tevent_req *req =
     911          26 :                 tevent_req_callback_data(subreq,
     912             :                 struct tevent_req);
     913           0 :         struct netlogon_creds_cli_lock_state *state =
     914          26 :                 tevent_req_data(req,
     915             :                 struct netlogon_creds_cli_lock_state);
     916           0 :         NTSTATUS status;
     917             : 
     918          26 :         status = g_lock_lock_recv(subreq);
     919          26 :         TALLOC_FREE(subreq);
     920          26 :         if (tevent_req_nterror(req, status)) {
     921           0 :                 return;
     922             :         }
     923          26 :         state->locked_state->is_glocked = true;
     924             : 
     925          26 :         status = netlogon_creds_cli_get_internal(state->locked_state->context,
     926             :                                                state, &state->creds);
     927          26 :         if (tevent_req_nterror(req, status)) {
     928           0 :                 return;
     929             :         }
     930          26 :         tevent_req_done(req);
     931             : }
     932             : 
     933         567 : 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         567 :         struct netlogon_creds_cli_fetch_state fstate = {
     938             :                 .status = NT_STATUS_INTERNAL_ERROR,
     939         567 :                 .proposed_flags = context->client.proposed_flags,
     940         567 :                 .required_flags = context->client.required_flags,
     941             :         };
     942           0 :         NTSTATUS status;
     943             : 
     944         567 :         fstate.mem_ctx = mem_ctx;
     945         567 :         status = dbwrap_parse_record(context->db.ctx,
     946             :                                      context->db.key_data,
     947             :                                      netlogon_creds_cli_fetch_parser,
     948             :                                      &fstate);
     949         567 :         if (!NT_STATUS_IS_OK(status)) {
     950          83 :                 return status;
     951             :         }
     952         484 :         if (!NT_STATUS_IS_OK(fstate.status)) {
     953           0 :                 return fstate.status;
     954             :         }
     955             : 
     956         484 :         if (context->server.cached_flags == fstate.creds->negotiate_flags) {
     957         359 :                 *pcreds = fstate.creds;
     958         359 :                 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         125 :         context->server.cached_flags = fstate.creds->negotiate_flags;
     994         125 :         context->server.try_validation6 = true;
     995         125 :         context->server.try_logon_ex = true;
     996         125 :         context->server.try_logon_with = true;
     997             : 
     998         125 :         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         125 :         if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
    1003          35 :                 context->server.try_validation6 = false;
    1004             :         }
    1005             : 
    1006         125 :         *pcreds = fstate.creds;
    1007         125 :         return NT_STATUS_OK;
    1008             : }
    1009             : 
    1010          26 : NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
    1011             :                         TALLOC_CTX *mem_ctx,
    1012             :                         struct netlogon_creds_CredentialState **creds)
    1013             : {
    1014           0 :         struct netlogon_creds_cli_lock_state *state =
    1015          26 :                 tevent_req_data(req,
    1016             :                 struct netlogon_creds_cli_lock_state);
    1017           0 :         NTSTATUS status;
    1018             : 
    1019          26 :         if (tevent_req_is_nterror(req, &status)) {
    1020           0 :                 tevent_req_received(req);
    1021           0 :                 return status;
    1022             :         }
    1023             : 
    1024          26 :         talloc_steal(state->creds, state->locked_state);
    1025          26 :         state->locked_state->creds = state->creds;
    1026          26 :         *creds = talloc_move(mem_ctx, &state->creds);
    1027          26 :         tevent_req_received(req);
    1028          26 :         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           0 :         struct tevent_context *ev;
    1037           0 :         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         251 : 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           0 :         struct tevent_req *req, *subreq;
    1076           0 :         struct netlogon_creds_cli_lck_state *state;
    1077           0 :         enum g_lock_type gtype;
    1078             : 
    1079         251 :         req = tevent_req_create(mem_ctx, &state,
    1080             :                                 struct netlogon_creds_cli_lck_state);
    1081         251 :         if (req == NULL) {
    1082           0 :                 return NULL;
    1083             :         }
    1084             : 
    1085         251 :         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         251 :         switch (type) {
    1092           0 :             case NETLOGON_CREDS_CLI_LCK_SHARED:
    1093           0 :                     gtype = G_LOCK_READ;
    1094           0 :                     break;
    1095         251 :             case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
    1096         251 :                     gtype = G_LOCK_WRITE;
    1097         251 :                     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         251 :         state->lck = talloc(state, struct netlogon_creds_cli_lck);
    1104         251 :         if (tevent_req_nomem(state->lck, req)) {
    1105           0 :                 return tevent_req_post(req, ev);
    1106             :         }
    1107         251 :         state->lck->context = context;
    1108         251 :         state->type = type;
    1109             : 
    1110         251 :         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         251 :         if (tevent_req_nomem(subreq, req)) {
    1116           0 :                 return tevent_req_post(req, ev);
    1117             :         }
    1118         251 :         tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
    1119             : 
    1120         251 :         return req;
    1121             : }
    1122             : 
    1123         251 : static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
    1124             : {
    1125         251 :         struct tevent_req *req = tevent_req_callback_data(
    1126             :                 subreq, struct tevent_req);
    1127         251 :         struct netlogon_creds_cli_lck_state *state = tevent_req_data(
    1128             :                 req, struct netlogon_creds_cli_lck_state);
    1129           0 :         NTSTATUS status;
    1130             : 
    1131         251 :         status = g_lock_lock_recv(subreq);
    1132         251 :         TALLOC_FREE(subreq);
    1133         251 :         if (tevent_req_nterror(req, status)) {
    1134           0 :                 return;
    1135             :         }
    1136             : 
    1137         251 :         state->lck->context->db.lock = state->type;
    1138         251 :         talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
    1139             : 
    1140         251 :         tevent_req_done(req);
    1141             : }
    1142             : 
    1143         251 : static int netlogon_creds_cli_lck_destructor(
    1144             :         struct netlogon_creds_cli_lck *lck)
    1145             : {
    1146         251 :         struct netlogon_creds_cli_context *ctx = lck->context;
    1147           0 :         NTSTATUS status;
    1148             : 
    1149         251 :         status = g_lock_unlock(ctx->db.g_ctx,
    1150             :                                string_term_tdb_data(ctx->db.key_name));
    1151         251 :         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         251 :         ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
    1156         251 :         return 0;
    1157             : }
    1158             : 
    1159         251 : NTSTATUS netlogon_creds_cli_lck_recv(
    1160             :         struct tevent_req *req, TALLOC_CTX *mem_ctx,
    1161             :         struct netlogon_creds_cli_lck **lck)
    1162             : {
    1163         251 :         struct netlogon_creds_cli_lck_state *state = tevent_req_data(
    1164             :                 req, struct netlogon_creds_cli_lck_state);
    1165           0 :         NTSTATUS status;
    1166             : 
    1167         251 :         if (tevent_req_is_nterror(req, &status)) {
    1168           0 :                 return status;
    1169             :         }
    1170         251 :         *lck = talloc_move(mem_ctx, &state->lck);
    1171         251 :         return NT_STATUS_OK;
    1172             : }
    1173             : 
    1174         251 : 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         251 :         TALLOC_CTX *frame = talloc_stackframe();
    1180           0 :         struct tevent_context *ev;
    1181           0 :         struct tevent_req *req;
    1182         251 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1183             : 
    1184         251 :         ev = samba_tevent_context_init(frame);
    1185         251 :         if (ev == NULL) {
    1186           0 :                 goto fail;
    1187             :         }
    1188         251 :         req = netlogon_creds_cli_lck_send(frame, ev, context, type);
    1189         251 :         if (req == NULL) {
    1190           0 :                 goto fail;
    1191             :         }
    1192         251 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1193           0 :                 goto fail;
    1194             :         }
    1195         251 :         status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
    1196         251 :  fail:
    1197         251 :         TALLOC_FREE(frame);
    1198         251 :         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         111 : 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           0 :         struct tevent_req *req;
    1232           0 :         struct netlogon_creds_cli_auth_state *state;
    1233           0 :         NTSTATUS status;
    1234             : 
    1235         111 :         req = tevent_req_create(mem_ctx, &state,
    1236             :                                 struct netlogon_creds_cli_auth_state);
    1237         111 :         if (req == NULL) {
    1238           0 :                 return NULL;
    1239             :         }
    1240             : 
    1241         111 :         state->ev = ev;
    1242         111 :         state->context = context;
    1243         111 :         state->binding_handle = b;
    1244         111 :         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         111 :         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         111 :         state->num_nt_hashes = num_nt_hashes;
    1254         111 :         state->idx_nt_hashes = 0;
    1255         111 :         state->nt_hashes = nt_hashes;
    1256             : 
    1257         111 :         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         111 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    1263             :                                                 context->server.computer);
    1264         111 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    1265           0 :                 return tevent_req_post(req, ev);
    1266             :         }
    1267             : 
    1268         111 :         state->try_auth3 = true;
    1269         111 :         state->try_auth2 = true;
    1270             : 
    1271         111 :         if (context->client.required_flags != 0) {
    1272         111 :                 state->require_auth2 = true;
    1273             :         }
    1274             : 
    1275         111 :         state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
    1276         111 :         state->current_flags = context->client.proposed_flags;
    1277             : 
    1278         111 :         status = dbwrap_purge(state->context->db.ctx,
    1279         111 :                               state->context->db.key_data);
    1280         111 :         if (tevent_req_nterror(req, status)) {
    1281           0 :                 return tevent_req_post(req, ev);
    1282             :         }
    1283             : 
    1284         111 :         netlogon_creds_cli_auth_challenge_start(req);
    1285         111 :         if (!tevent_req_is_in_progress(req)) {
    1286           0 :                 return tevent_req_post(req, ev);
    1287             :         }
    1288             : 
    1289         111 :         return req;
    1290             : }
    1291             : 
    1292             : static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
    1293             : 
    1294         118 : static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
    1295             : {
    1296           0 :         struct netlogon_creds_cli_auth_state *state =
    1297         118 :                 tevent_req_data(req,
    1298             :                 struct netlogon_creds_cli_auth_state);
    1299           0 :         struct tevent_req *subreq;
    1300             : 
    1301         118 :         TALLOC_FREE(state->creds);
    1302             : 
    1303         118 :         netlogon_creds_random_challenge(&state->client_challenge);
    1304             : 
    1305         118 :         subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
    1306             :                                                 state->binding_handle,
    1307         118 :                                                 state->srv_name_slash,
    1308         118 :                                                 state->context->client.computer,
    1309             :                                                 &state->client_challenge,
    1310             :                                                 &state->server_challenge);
    1311         118 :         if (tevent_req_nomem(subreq, req)) {
    1312           0 :                 return;
    1313             :         }
    1314         118 :         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         118 : static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
    1322             : {
    1323           0 :         struct tevent_req *req =
    1324         118 :                 tevent_req_callback_data(subreq,
    1325             :                 struct tevent_req);
    1326           0 :         struct netlogon_creds_cli_auth_state *state =
    1327         118 :                 tevent_req_data(req,
    1328             :                 struct netlogon_creds_cli_auth_state);
    1329           0 :         NTSTATUS status;
    1330           0 :         NTSTATUS result;
    1331             : 
    1332         118 :         status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
    1333         118 :         TALLOC_FREE(subreq);
    1334         118 :         if (tevent_req_nterror(req, status)) {
    1335           0 :                 return;
    1336             :         }
    1337         118 :         if (tevent_req_nterror(req, result)) {
    1338           0 :                 return;
    1339             :         }
    1340             : 
    1341         118 :         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         236 :         state->creds = netlogon_creds_client_init(state,
    1348         118 :                                                   state->context->client.account,
    1349         118 :                                                   state->context->client.computer,
    1350         118 :                                                   state->context->client.type,
    1351         118 :                                                   &state->client_challenge,
    1352         118 :                                                   &state->server_challenge,
    1353             :                                                   state->used_nt_hash,
    1354             :                                                   &state->client_credential,
    1355             :                                                   state->current_flags);
    1356         118 :         if (tevent_req_nomem(state->creds, req)) {
    1357           0 :                 return;
    1358             :         }
    1359             : 
    1360         118 :         if (state->try_auth3) {
    1361         118 :                 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
    1362             :                                                 state->binding_handle,
    1363         118 :                                                 state->srv_name_slash,
    1364         118 :                                                 state->context->client.account,
    1365         118 :                                                 state->context->client.type,
    1366         118 :                                                 state->context->client.computer,
    1367             :                                                 &state->client_credential,
    1368             :                                                 &state->server_credential,
    1369         118 :                                                 &state->creds->negotiate_flags,
    1370             :                                                 &state->rid);
    1371         118 :                 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         118 :         tevent_req_set_callback(subreq,
    1405             :                                 netlogon_creds_cli_auth_srvauth_done,
    1406             :                                 req);
    1407             : }
    1408             : 
    1409         118 : static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
    1410             : {
    1411           0 :         struct tevent_req *req =
    1412         118 :                 tevent_req_callback_data(subreq,
    1413             :                 struct tevent_req);
    1414           0 :         struct netlogon_creds_cli_auth_state *state =
    1415         118 :                 tevent_req_data(req,
    1416             :                 struct netlogon_creds_cli_auth_state);
    1417           0 :         NTSTATUS status;
    1418           0 :         NTSTATUS result;
    1419           0 :         bool ok;
    1420           0 :         enum ndr_err_code ndr_err;
    1421           0 :         DATA_BLOB blob;
    1422           0 :         TDB_DATA data;
    1423           0 :         bool downgraded;
    1424             : 
    1425         118 :         if (state->try_auth3) {
    1426         118 :                 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
    1427             :                                                               &result);
    1428         118 :                 TALLOC_FREE(subreq);
    1429         118 :                 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         118 :                 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         118 :         if (!NT_STATUS_IS_OK(result) &&
    1464          14 :             !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
    1465             :         {
    1466           0 :                 tevent_req_nterror(req, result);
    1467           0 :                 return;
    1468             :         }
    1469             : 
    1470         118 :         downgraded = netlogon_creds_cli_downgraded(
    1471         118 :                         state->creds->negotiate_flags,
    1472         118 :                         state->context->client.proposed_flags,
    1473         118 :                         state->context->client.required_flags);
    1474         118 :         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         118 :         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
    1484          14 :                 uint32_t tmp_flags = state->context->client.proposed_flags;
    1485          14 :                 if ((state->current_flags == tmp_flags) &&
    1486           7 :                     (state->creds->negotiate_flags != tmp_flags))
    1487             :                 {
    1488             :                         /*
    1489             :                          * lets retry with the negotiated flags
    1490             :                          */
    1491           7 :                         state->current_flags = state->creds->negotiate_flags;
    1492           7 :                         netlogon_creds_cli_auth_challenge_start(req);
    1493          14 :                         return;
    1494             :                 }
    1495             : 
    1496           7 :                 state->idx_nt_hashes += 1;
    1497           7 :                 if (state->idx_nt_hashes >= state->num_nt_hashes) {
    1498             :                         /*
    1499             :                          * we already retried, giving up...
    1500             :                          */
    1501           7 :                         tevent_req_nterror(req, result);
    1502           7 :                         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         104 :         ok = netlogon_creds_client_check(state->creds,
    1515         104 :                                          &state->server_credential);
    1516         104 :         if (!ok) {
    1517           0 :                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
    1518           0 :                 return;
    1519             :         }
    1520             : 
    1521         104 :         ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
    1522             :                 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
    1523         104 :         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         104 :         data.dptr = blob.data;
    1530         104 :         data.dsize = blob.length;
    1531             : 
    1532         104 :         status = dbwrap_store(state->context->db.ctx,
    1533         104 :                               state->context->db.key_data,
    1534             :                               data, TDB_REPLACE);
    1535         104 :         if (tevent_req_nterror(req, status)) {
    1536           0 :                 return;
    1537             :         }
    1538             : 
    1539         104 :         tevent_req_done(req);
    1540             : }
    1541             : 
    1542         111 : NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
    1543             :                                       uint8_t *idx_nt_hashes)
    1544             : {
    1545           0 :         struct netlogon_creds_cli_auth_state *state =
    1546         111 :                 tevent_req_data(req,
    1547             :                 struct netlogon_creds_cli_auth_state);
    1548           0 :         NTSTATUS status;
    1549             : 
    1550         111 :         *idx_nt_hashes = 0;
    1551             : 
    1552         111 :         if (tevent_req_is_nterror(req, &status)) {
    1553           7 :                 tevent_req_received(req);
    1554           7 :                 return status;
    1555             :         }
    1556             : 
    1557         104 :         *idx_nt_hashes = state->idx_nt_hashes;
    1558         104 :         tevent_req_received(req);
    1559         104 :         return NT_STATUS_OK;
    1560             : }
    1561             : 
    1562         111 : 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         111 :         TALLOC_CTX *frame = talloc_stackframe();
    1569           0 :         struct tevent_context *ev;
    1570           0 :         struct tevent_req *req;
    1571         111 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1572             : 
    1573         111 :         *idx_nt_hashes = 0;
    1574             : 
    1575         111 :         ev = samba_tevent_context_init(frame);
    1576         111 :         if (ev == NULL) {
    1577           0 :                 goto fail;
    1578             :         }
    1579         111 :         req = netlogon_creds_cli_auth_send(frame, ev, context, b,
    1580             :                                            num_nt_hashes, nt_hashes);
    1581         111 :         if (req == NULL) {
    1582           0 :                 goto fail;
    1583             :         }
    1584         111 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1585           0 :                 goto fail;
    1586             :         }
    1587         111 :         status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
    1588         111 :  fail:
    1589         111 :         TALLOC_FREE(frame);
    1590         111 :         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         103 : 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           0 :         struct tevent_req *req;
    1617           0 :         struct netlogon_creds_cli_check_state *state;
    1618           0 :         struct tevent_req *subreq;
    1619           0 :         enum dcerpc_AuthType auth_type;
    1620           0 :         enum dcerpc_AuthLevel auth_level;
    1621           0 :         NTSTATUS status;
    1622             : 
    1623         103 :         req = tevent_req_create(mem_ctx, &state,
    1624             :                                 struct netlogon_creds_cli_check_state);
    1625         103 :         if (req == NULL) {
    1626           0 :                 return NULL;
    1627             :         }
    1628             : 
    1629         103 :         state->ev = ev;
    1630         103 :         state->context = context;
    1631         103 :         state->binding_handle = b;
    1632             : 
    1633         103 :         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         103 :         status = netlogon_creds_cli_get_internal(context, state,
    1639         103 :                                                  &state->creds);
    1640         103 :         if (tevent_req_nterror(req, status)) {
    1641           0 :                 return tevent_req_post(req, ev);
    1642             :         }
    1643             : 
    1644         103 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    1645             :                                                 context->server.computer);
    1646         103 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    1647           0 :                 return tevent_req_post(req, ev);
    1648             :         }
    1649             : 
    1650         103 :         dcerpc_binding_handle_auth_info(state->binding_handle,
    1651             :                                         &auth_type, &auth_level);
    1652             : 
    1653         103 :         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         103 :         switch (auth_level) {
    1659         103 :         case DCERPC_AUTH_LEVEL_INTEGRITY:
    1660             :         case DCERPC_AUTH_LEVEL_PRIVACY:
    1661         103 :                 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         103 :         tevent_req_defer_callback(req, state->ev);
    1672             : 
    1673         103 :         status = netlogon_creds_client_authenticator(state->creds,
    1674         103 :                                                      &state->req_auth);
    1675         103 :         if (tevent_req_nterror(req, status)) {
    1676           0 :                 return tevent_req_post(req, ev);
    1677             :         }
    1678         103 :         ZERO_STRUCT(state->rep_auth);
    1679             : 
    1680         103 :         subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
    1681         103 :                                                 state->binding_handle,
    1682         103 :                                                 state->srv_name_slash,
    1683         103 :                                                 state->context->client.computer,
    1684         103 :                                                 &state->req_auth,
    1685         103 :                                                 &state->rep_auth,
    1686             :                                                 1,
    1687         103 :                                                 &state->caps);
    1688         103 :         if (tevent_req_nomem(subreq, req)) {
    1689           0 :                 return tevent_req_post(req, ev);
    1690             :         }
    1691             : 
    1692         103 :         tevent_req_set_callback(subreq,
    1693             :                                 netlogon_creds_cli_check_caps,
    1694             :                                 req);
    1695             : 
    1696         103 :         return req;
    1697             : }
    1698             : 
    1699           0 : static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
    1700             :                                              NTSTATUS status)
    1701             : {
    1702           0 :         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         103 : static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
    1724             : {
    1725           0 :         struct tevent_req *req =
    1726         103 :                 tevent_req_callback_data(subreq,
    1727             :                 struct tevent_req);
    1728           0 :         struct netlogon_creds_cli_check_state *state =
    1729         103 :                 tevent_req_data(req,
    1730             :                 struct netlogon_creds_cli_check_state);
    1731           0 :         NTSTATUS status;
    1732           0 :         NTSTATUS result;
    1733           0 :         bool ok;
    1734             : 
    1735         103 :         status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
    1736             :                                                        &result);
    1737         103 :         TALLOC_FREE(subreq);
    1738         103 :         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         103 :         if (tevent_req_nterror(req, status)) {
    1789           0 :                 netlogon_creds_cli_check_cleanup(req, status);
    1790           0 :                 return;
    1791             :         }
    1792             : 
    1793         103 :         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         103 :         ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
    1825         103 :         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         103 :         if (tevent_req_nterror(req, result)) {
    1833           0 :                 netlogon_creds_cli_check_cleanup(req, result);
    1834           0 :                 return;
    1835             :         }
    1836             : 
    1837         103 :         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         103 :         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         103 :         status = netlogon_creds_cli_store_internal(state->context,
    1860             :                                                    state->creds);
    1861         103 :         if (tevent_req_nterror(req, status)) {
    1862           0 :                 return;
    1863             :         }
    1864             : 
    1865         103 :         tevent_req_done(req);
    1866             : }
    1867             : 
    1868         103 : NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
    1869             :                                        union netr_Capabilities *capabilities)
    1870             : {
    1871         103 :         struct netlogon_creds_cli_check_state *state = tevent_req_data(
    1872             :                 req, struct netlogon_creds_cli_check_state);
    1873           0 :         NTSTATUS status;
    1874             : 
    1875         103 :         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         103 :         if (capabilities != NULL) {
    1882           0 :                 *capabilities = state->caps;
    1883             :         }
    1884             : 
    1885         103 :         tevent_req_received(req);
    1886         103 :         return NT_STATUS_OK;
    1887             : }
    1888             : 
    1889         103 : NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
    1890             :                                   struct dcerpc_binding_handle *b,
    1891             :                                   union netr_Capabilities *capabilities)
    1892             : {
    1893         103 :         TALLOC_CTX *frame = talloc_stackframe();
    1894           0 :         struct tevent_context *ev;
    1895           0 :         struct tevent_req *req;
    1896         103 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1897             : 
    1898         103 :         ev = samba_tevent_context_init(frame);
    1899         103 :         if (ev == NULL) {
    1900           0 :                 goto fail;
    1901             :         }
    1902         103 :         req = netlogon_creds_cli_check_send(frame, ev, context, b);
    1903         103 :         if (req == NULL) {
    1904           0 :                 goto fail;
    1905             :         }
    1906         103 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1907           0 :                 goto fail;
    1908             :         }
    1909         103 :         status = netlogon_creds_cli_check_recv(req, capabilities);
    1910         103 :  fail:
    1911         103 :         TALLOC_FREE(frame);
    1912         103 :         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           8 : 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           0 :         struct tevent_req *req;
    1947           0 :         struct netlogon_creds_cli_ServerPasswordSet_state *state;
    1948           0 :         struct tevent_req *subreq;
    1949           0 :         bool ok;
    1950             : 
    1951           8 :         req = tevent_req_create(mem_ctx, &state,
    1952             :                                 struct netlogon_creds_cli_ServerPasswordSet_state);
    1953           8 :         if (req == NULL) {
    1954           0 :                 return NULL;
    1955             :         }
    1956             : 
    1957           8 :         state->ev = ev;
    1958           8 :         state->context = context;
    1959           8 :         state->binding_handle = b;
    1960             : 
    1961           8 :         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           8 :         mdfour(state->samr_password.hash, new_password->data, new_password->length);
    1970             : 
    1971             :         /*
    1972             :          * netr_ServerPasswordSet2
    1973             :          */
    1974           8 :         ok = set_pw_in_buffer(state->samr_crypt_password.data,
    1975             :                               new_password);
    1976           8 :         if (!ok) {
    1977           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
    1978           0 :                 return tevent_req_post(req, ev);
    1979             :         }
    1980             : 
    1981           8 :         if (new_version != NULL) {
    1982           0 :                 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           0 :                 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           8 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    2005             :                                                 context->server.computer);
    2006           8 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    2007           0 :                 return tevent_req_post(req, ev);
    2008             :         }
    2009             : 
    2010           8 :         dcerpc_binding_handle_auth_info(state->binding_handle,
    2011           8 :                                         &state->auth_type,
    2012           8 :                                         &state->auth_level);
    2013             : 
    2014           8 :         subreq = netlogon_creds_cli_lock_send(state, state->ev,
    2015           8 :                                               state->context);
    2016           8 :         if (tevent_req_nomem(subreq, req)) {
    2017           0 :                 return tevent_req_post(req, ev);
    2018             :         }
    2019             : 
    2020           8 :         tevent_req_set_callback(subreq,
    2021             :                                 netlogon_creds_cli_ServerPasswordSet_locked,
    2022             :                                 req);
    2023             : 
    2024           8 :         return req;
    2025             : }
    2026             : 
    2027           0 : static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
    2028             :                                                          NTSTATUS status)
    2029             : {
    2030           0 :         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           8 : static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
    2057             : {
    2058           0 :         struct tevent_req *req =
    2059           8 :                 tevent_req_callback_data(subreq,
    2060             :                 struct tevent_req);
    2061           0 :         struct netlogon_creds_cli_ServerPasswordSet_state *state =
    2062           8 :                 tevent_req_data(req,
    2063             :                 struct netlogon_creds_cli_ServerPasswordSet_state);
    2064           0 :         NTSTATUS status;
    2065             : 
    2066           8 :         status = netlogon_creds_cli_lock_recv(subreq, state,
    2067             :                                               &state->creds);
    2068           8 :         TALLOC_FREE(subreq);
    2069           8 :         if (tevent_req_nterror(req, status)) {
    2070           0 :                 return;
    2071             :         }
    2072             : 
    2073           8 :         if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
    2074           8 :                 switch (state->auth_level) {
    2075           8 :                 case DCERPC_AUTH_LEVEL_INTEGRITY:
    2076             :                 case DCERPC_AUTH_LEVEL_PRIVACY:
    2077           8 :                         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           8 :         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           8 :         tevent_req_defer_callback(req, state->ev);
    2109             : 
    2110           8 :         state->tmp_creds = *state->creds;
    2111           8 :         status = netlogon_creds_client_authenticator(&state->tmp_creds,
    2112             :                                                      &state->req_auth);
    2113           8 :         if (tevent_req_nterror(req, status)) {
    2114           0 :                 return;
    2115             :         }
    2116           8 :         ZERO_STRUCT(state->rep_auth);
    2117             : 
    2118           8 :         if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
    2119             : 
    2120           8 :                 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
    2121           8 :                         status = netlogon_creds_aes_encrypt(&state->tmp_creds,
    2122           8 :                                                             state->samr_crypt_password.data,
    2123             :                                                             516);
    2124           8 :                         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           8 :                 memcpy(state->netr_crypt_password.data,
    2139           8 :                        state->samr_crypt_password.data, 512);
    2140           8 :                 state->netr_crypt_password.length =
    2141           8 :                         IVAL(state->samr_crypt_password.data, 512);
    2142             : 
    2143           8 :                 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
    2144             :                                         state->binding_handle,
    2145           8 :                                         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           8 :                 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           8 :         tevent_req_set_callback(subreq,
    2182             :                                 netlogon_creds_cli_ServerPasswordSet_done,
    2183             :                                 req);
    2184             : }
    2185             : 
    2186           8 : static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
    2187             : {
    2188           0 :         struct tevent_req *req =
    2189           8 :                 tevent_req_callback_data(subreq,
    2190             :                 struct tevent_req);
    2191           0 :         struct netlogon_creds_cli_ServerPasswordSet_state *state =
    2192           8 :                 tevent_req_data(req,
    2193             :                 struct netlogon_creds_cli_ServerPasswordSet_state);
    2194           0 :         NTSTATUS status;
    2195           0 :         NTSTATUS result;
    2196           0 :         bool ok;
    2197             : 
    2198           8 :         if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
    2199           8 :                 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
    2200             :                                                              &result);
    2201           8 :                 TALLOC_FREE(subreq);
    2202           8 :                 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           8 :         ok = netlogon_creds_client_check(&state->tmp_creds,
    2217           8 :                                          &state->rep_auth.cred);
    2218           8 :         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           8 :         if (tevent_req_nterror(req, result)) {
    2226           0 :                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
    2227           0 :                 return;
    2228             :         }
    2229             : 
    2230           8 :         dcerpc_binding_handle_set_timeout(state->binding_handle,
    2231             :                                           state->old_timeout);
    2232             : 
    2233           8 :         *state->creds = state->tmp_creds;
    2234           8 :         status = netlogon_creds_cli_store(state->context,
    2235             :                                           state->creds);
    2236           8 :         TALLOC_FREE(state->creds);
    2237           8 :         if (tevent_req_nterror(req, status)) {
    2238           0 :                 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
    2239           0 :                 return;
    2240             :         }
    2241             : 
    2242           8 :         tevent_req_done(req);
    2243             : }
    2244             : 
    2245           8 : NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
    2246             : {
    2247           0 :         NTSTATUS status;
    2248             : 
    2249           8 :         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           8 :         tevent_req_received(req);
    2256           8 :         return NT_STATUS_OK;
    2257             : }
    2258             : 
    2259           8 : 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           8 :         TALLOC_CTX *frame = talloc_stackframe();
    2266           0 :         struct tevent_context *ev;
    2267           0 :         struct tevent_req *req;
    2268           8 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    2269             : 
    2270           8 :         ev = samba_tevent_context_init(frame);
    2271           8 :         if (ev == NULL) {
    2272           0 :                 goto fail;
    2273             :         }
    2274           8 :         req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
    2275             :                                                         new_password,
    2276             :                                                         new_version);
    2277           8 :         if (req == NULL) {
    2278           0 :                 goto fail;
    2279             :         }
    2280           8 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    2281           0 :                 goto fail;
    2282             :         }
    2283           8 :         status = netlogon_creds_cli_ServerPasswordSet_recv(req);
    2284           8 :  fail:
    2285           8 :         TALLOC_FREE(frame);
    2286           8 :         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          42 : 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           0 :         struct tevent_req *req;
    2350           0 :         struct netlogon_creds_cli_LogonSamLogon_state *state;
    2351             : 
    2352          42 :         req = tevent_req_create(mem_ctx, &state,
    2353             :                                 struct netlogon_creds_cli_LogonSamLogon_state);
    2354          42 :         if (req == NULL) {
    2355           0 :                 return NULL;
    2356             :         }
    2357             : 
    2358          42 :         state->ev = ev;
    2359          42 :         state->context = context;
    2360          42 :         state->binding_handle = b;
    2361             : 
    2362          42 :         state->logon_level = logon_level;
    2363          42 :         state->const_logon = logon;
    2364          42 :         state->flags = flags;
    2365             : 
    2366          42 :         state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
    2367             :                                                 context->server.computer);
    2368          42 :         if (tevent_req_nomem(state->srv_name_slash, req)) {
    2369           0 :                 return tevent_req_post(req, ev);
    2370             :         }
    2371             : 
    2372          42 :         switch (logon_level) {
    2373           6 :         case NetlogonInteractiveInformation:
    2374             :         case NetlogonInteractiveTransitiveInformation:
    2375             :         case NetlogonServiceInformation:
    2376             :         case NetlogonServiceTransitiveInformation:
    2377             :         case NetlogonGenericInformation:
    2378           6 :                 state->user_encrypt = true;
    2379           6 :                 break;
    2380             : 
    2381          36 :         case NetlogonNetworkInformation:
    2382             :         case NetlogonNetworkTransitiveInformation:
    2383          36 :                 break;
    2384             :         }
    2385             : 
    2386          42 :         state->validation = talloc_zero(state, union netr_Validation);
    2387          42 :         if (tevent_req_nomem(state->validation, req)) {
    2388           0 :                 return tevent_req_post(req, ev);
    2389             :         }
    2390             : 
    2391          42 :         netlogon_creds_cli_LogonSamLogon_start(req);
    2392          42 :         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          42 :         tevent_req_defer_callback(req, state->ev);
    2401          42 :         return req;
    2402             : }
    2403             : 
    2404          24 : static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
    2405             :                                                      NTSTATUS status)
    2406             : {
    2407           0 :         struct netlogon_creds_cli_LogonSamLogon_state *state =
    2408          24 :                 tevent_req_data(req,
    2409             :                 struct netlogon_creds_cli_LogonSamLogon_state);
    2410             : 
    2411          24 :         if (state->lk_creds == NULL) {
    2412          24 :                 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          60 : static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
    2455             : {
    2456           0 :         struct netlogon_creds_cli_LogonSamLogon_state *state =
    2457          60 :                 tevent_req_data(req,
    2458             :                 struct netlogon_creds_cli_LogonSamLogon_state);
    2459           0 :         struct tevent_req *subreq;
    2460           0 :         NTSTATUS status;
    2461           0 :         enum dcerpc_AuthType auth_type;
    2462           0 :         enum dcerpc_AuthLevel auth_level;
    2463             : 
    2464          60 :         TALLOC_FREE(state->ro_creds);
    2465          60 :         TALLOC_FREE(state->logon);
    2466          60 :         ZERO_STRUCTP(state->validation);
    2467             : 
    2468          60 :         dcerpc_binding_handle_auth_info(state->binding_handle,
    2469             :                                         &auth_type, &auth_level);
    2470             : 
    2471          60 :         state->try_logon_ex = state->context->server.try_logon_ex;
    2472          60 :         state->try_validation6 = state->context->server.try_validation6;
    2473             : 
    2474          60 :         if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
    2475          36 :                 state->try_logon_ex = false;
    2476             :         }
    2477             : 
    2478          60 :         if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
    2479          36 :                 state->try_validation6 = false;
    2480             :         }
    2481             : 
    2482          60 :         if (state->try_logon_ex) {
    2483          24 :                 if (state->try_validation6) {
    2484          24 :                         state->validation_level = 6;
    2485             :                 } else {
    2486           0 :                         state->validation_level = 3;
    2487           0 :                         state->user_encrypt = true;
    2488             :                 }
    2489             : 
    2490          24 :                 state->logon = netlogon_creds_shallow_copy_logon(state,
    2491             :                                                         state->logon_level,
    2492             :                                                         state->const_logon);
    2493          24 :                 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          24 :                 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          24 :                 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
    2522             :                                                 state->binding_handle,
    2523          24 :                                                 state->srv_name_slash,
    2524          24 :                                                 state->context->client.computer,
    2525             :                                                 state->logon_level,
    2526             :                                                 state->logon,
    2527          24 :                                                 state->validation_level,
    2528             :                                                 state->validation,
    2529             :                                                 &state->authoritative,
    2530             :                                                 &state->flags);
    2531          24 :                 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          24 :                 tevent_req_set_callback(subreq,
    2537             :                                         netlogon_creds_cli_LogonSamLogon_done,
    2538             :                                         req);
    2539          24 :                 return;
    2540             :         }
    2541             : 
    2542          36 :         if (state->lk_creds == NULL) {
    2543          18 :                 subreq = netlogon_creds_cli_lock_send(state, state->ev,
    2544             :                                                       state->context);
    2545          18 :                 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          18 :                 tevent_req_set_callback(subreq,
    2551             :                                         netlogon_creds_cli_LogonSamLogon_done,
    2552             :                                         req);
    2553          18 :                 return;
    2554             :         }
    2555             : 
    2556          18 :         state->tmp_creds = *state->lk_creds;
    2557          18 :         status = netlogon_creds_client_authenticator(&state->tmp_creds,
    2558             :                                                      &state->req_auth);
    2559          18 :         if (tevent_req_nterror(req, status)) {
    2560           0 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2561           0 :                 return;
    2562             :         }
    2563          18 :         ZERO_STRUCT(state->rep_auth);
    2564             : 
    2565          18 :         state->logon = netlogon_creds_shallow_copy_logon(state,
    2566             :                                                 state->logon_level,
    2567             :                                                 state->const_logon);
    2568          18 :         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          18 :         status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
    2575             :                                                        state->logon_level,
    2576             :                                                        state->logon);
    2577          18 :         if (tevent_req_nterror(req, status)) {
    2578           0 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2579           0 :                 return;
    2580             :         }
    2581             : 
    2582          18 :         state->validation_level = 3;
    2583             : 
    2584          18 :         if (state->context->server.try_logon_with) {
    2585          18 :                 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
    2586             :                                                 state->binding_handle,
    2587          18 :                                                 state->srv_name_slash,
    2588          18 :                                                 state->context->client.computer,
    2589             :                                                 &state->req_auth,
    2590             :                                                 &state->rep_auth,
    2591             :                                                 state->logon_level,
    2592             :                                                 state->logon,
    2593          18 :                                                 state->validation_level,
    2594             :                                                 state->validation,
    2595             :                                                 &state->authoritative,
    2596             :                                                 &state->flags);
    2597          18 :                 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          18 :         tevent_req_set_callback(subreq,
    2624             :                                 netlogon_creds_cli_LogonSamLogon_done,
    2625             :                                 req);
    2626             : }
    2627             : 
    2628          60 : static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
    2629             : {
    2630           0 :         struct tevent_req *req =
    2631          60 :                 tevent_req_callback_data(subreq,
    2632             :                 struct tevent_req);
    2633           0 :         struct netlogon_creds_cli_LogonSamLogon_state *state =
    2634          60 :                 tevent_req_data(req,
    2635             :                 struct netlogon_creds_cli_LogonSamLogon_state);
    2636           0 :         NTSTATUS status;
    2637           0 :         NTSTATUS result;
    2638           0 :         bool ok;
    2639             : 
    2640          60 :         if (state->try_logon_ex) {
    2641          24 :                 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
    2642          24 :                                                           state->validation,
    2643             :                                                           &result);
    2644          24 :                 TALLOC_FREE(subreq);
    2645          24 :                 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          24 :                 if (tevent_req_nterror(req, status)) {
    2652           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2653           0 :                         return;
    2654             :                 }
    2655             : 
    2656          24 :                 if ((state->validation_level == 6) &&
    2657          24 :                     (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
    2658          24 :                      NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
    2659          24 :                      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          24 :                 if (tevent_req_nterror(req, result)) {
    2667           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
    2668           0 :                         return;
    2669             :                 }
    2670             : 
    2671          24 :                 if (state->ro_creds == NULL) {
    2672          24 :                         tevent_req_done(req);
    2673          24 :                         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          36 :         if (state->lk_creds == NULL) {
    2703          18 :                 status = netlogon_creds_cli_lock_recv(subreq, state,
    2704             :                                                       &state->lk_creds);
    2705          18 :                 TALLOC_FREE(subreq);
    2706          18 :                 if (tevent_req_nterror(req, status)) {
    2707           0 :                         netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2708           0 :                         return;
    2709             :                 }
    2710             : 
    2711          18 :                 netlogon_creds_cli_LogonSamLogon_start(req);
    2712          18 :                 return;
    2713             :         }
    2714             : 
    2715          18 :         if (state->context->server.try_logon_with) {
    2716          18 :                 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
    2717          18 :                                                                  state->validation,
    2718             :                                                                  &result);
    2719          18 :                 TALLOC_FREE(subreq);
    2720          18 :                 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          18 :                 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          18 :         ok = netlogon_creds_client_check(&state->tmp_creds,
    2741          18 :                                          &state->rep_auth.cred);
    2742          18 :         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          18 :         *state->lk_creds = state->tmp_creds;
    2750          18 :         status = netlogon_creds_cli_store(state->context,
    2751             :                                           state->lk_creds);
    2752          18 :         TALLOC_FREE(state->lk_creds);
    2753             : 
    2754          18 :         if (tevent_req_nterror(req, status)) {
    2755           0 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2756           0 :                 return;
    2757             :         }
    2758             : 
    2759          18 :         if (tevent_req_nterror(req, result)) {
    2760          12 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
    2761          12 :                 return;
    2762             :         }
    2763             : 
    2764           6 :         status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
    2765           6 :                                                             state->validation_level,
    2766             :                                                             state->validation);
    2767           6 :         if (tevent_req_nterror(req, status)) {
    2768           0 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
    2769           0 :                 return;
    2770             :         }
    2771             : 
    2772           6 :         tevent_req_done(req);
    2773             : }
    2774             : 
    2775          42 : 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           0 :         struct netlogon_creds_cli_LogonSamLogon_state *state =
    2783          42 :                 tevent_req_data(req,
    2784             :                 struct netlogon_creds_cli_LogonSamLogon_state);
    2785           0 :         NTSTATUS status;
    2786             : 
    2787             :         /* authoritative is also returned on error */
    2788          42 :         *authoritative = state->authoritative;
    2789             : 
    2790          42 :         if (tevent_req_is_nterror(req, &status)) {
    2791          12 :                 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
    2792          12 :                 tevent_req_received(req);
    2793          12 :                 return status;
    2794             :         }
    2795             : 
    2796          30 :         *validation_level = state->validation_level;
    2797          30 :         *validation = talloc_move(mem_ctx, &state->validation);
    2798          30 :         *flags = state->flags;
    2799             : 
    2800          30 :         tevent_req_received(req);
    2801          30 :         return NT_STATUS_OK;
    2802             : }
    2803             : 
    2804          42 : 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          42 :         TALLOC_CTX *frame = talloc_stackframe();
    2816           0 :         struct tevent_context *ev;
    2817           0 :         struct tevent_req *req;
    2818          42 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    2819             : 
    2820          42 :         ev = samba_tevent_context_init(frame);
    2821          42 :         if (ev == NULL) {
    2822           0 :                 goto fail;
    2823             :         }
    2824          42 :         req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
    2825             :                                                     logon_level, logon,
    2826             :                                                     *flags);
    2827          42 :         if (req == NULL) {
    2828           0 :                 goto fail;
    2829             :         }
    2830          42 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    2831           0 :                 goto fail;
    2832             :         }
    2833          42 :         status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
    2834             :                                                        validation_level,
    2835             :                                                        validation,
    2836             :                                                        authoritative,
    2837             :                                                        flags);
    2838          42 :  fail:
    2839          42 :         TALLOC_FREE(frame);
    2840          42 :         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           0 :         struct tevent_req *req;
    2875           0 :         struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
    2876           0 :         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           0 :         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           0 :         struct tevent_req *req =
    2944           0 :                 tevent_req_callback_data(subreq,
    2945             :                 struct tevent_req);
    2946           0 :         struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
    2947           0 :                 tevent_req_data(req,
    2948             :                 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
    2949           0 :         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           0 :         struct tevent_req *req =
    3023           0 :                 tevent_req_callback_data(subreq,
    3024             :                 struct tevent_req);
    3025           0 :         struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
    3026           0 :                 tevent_req_data(req,
    3027             :                 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
    3028           0 :         NTSTATUS status;
    3029           0 :         NTSTATUS result;
    3030           0 :         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           0 :         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           0 :         struct tevent_context *ev;
    3097           0 :         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           0 :         struct tevent_req *req;
    3149           0 :         struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
    3150           0 :         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           0 :         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           0 :         struct tevent_req *req =
    3214           0 :                 tevent_req_callback_data(subreq,
    3215             :                 struct tevent_req);
    3216           0 :         struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
    3217           0 :                 tevent_req_data(req,
    3218             :                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
    3219           0 :         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           0 :         struct tevent_req *req =
    3280           0 :                 tevent_req_callback_data(subreq,
    3281             :                 struct tevent_req);
    3282           0 :         struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
    3283           0 :                 tevent_req_data(req,
    3284             :                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
    3285           0 :         NTSTATUS status;
    3286           0 :         NTSTATUS result;
    3287           0 :         const struct samr_Password zero = {};
    3288           0 :         bool cmp;
    3289           0 :         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           0 :         struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
    3359           0 :                 tevent_req_data(req,
    3360             :                 struct netlogon_creds_cli_ServerGetTrustInfo_state);
    3361           0 :         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           0 :         struct tevent_context *ev;
    3393           0 :         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           0 :         struct tevent_req *req;
    3445           0 :         struct netlogon_creds_cli_GetForestTrustInformation_state *state;
    3446           0 :         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           0 :         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           0 :         struct tevent_req *req =
    3512           0 :                 tevent_req_callback_data(subreq,
    3513             :                 struct tevent_req);
    3514           0 :         struct netlogon_creds_cli_GetForestTrustInformation_state *state =
    3515           0 :                 tevent_req_data(req,
    3516             :                 struct netlogon_creds_cli_GetForestTrustInformation_state);
    3517           0 :         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           0 :         struct tevent_req *req =
    3590           0 :                 tevent_req_callback_data(subreq,
    3591             :                 struct tevent_req);
    3592           0 :         struct netlogon_creds_cli_GetForestTrustInformation_state *state =
    3593           0 :                 tevent_req_data(req,
    3594             :                 struct netlogon_creds_cli_GetForestTrustInformation_state);
    3595           0 :         NTSTATUS status;
    3596           0 :         NTSTATUS result;
    3597           0 :         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           0 :         struct netlogon_creds_cli_GetForestTrustInformation_state *state =
    3645           0 :                 tevent_req_data(req,
    3646             :                 struct netlogon_creds_cli_GetForestTrustInformation_state);
    3647           0 :         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           0 :         struct tevent_context *ev;
    3669           0 :         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           0 :         struct tevent_req *req;
    3718           0 :         struct netlogon_creds_cli_SendToSam_state *state;
    3719           0 :         struct tevent_req *subreq;
    3720           0 :         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           0 :         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           0 :         struct tevent_req *req =
    3792           0 :                 tevent_req_callback_data(subreq,
    3793             :                 struct tevent_req);
    3794           0 :         struct netlogon_creds_cli_SendToSam_state *state =
    3795           0 :                 tevent_req_data(req,
    3796             :                 struct netlogon_creds_cli_SendToSam_state);
    3797           0 :         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           0 :         struct tevent_req *req =
    3888           0 :                 tevent_req_callback_data(subreq,
    3889             :                 struct tevent_req);
    3890           0 :         struct netlogon_creds_cli_SendToSam_state *state =
    3891           0 :                 tevent_req_data(req,
    3892             :                 struct netlogon_creds_cli_SendToSam_state);
    3893           0 :         NTSTATUS status;
    3894           0 :         NTSTATUS result;
    3895           0 :         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           0 :         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           0 :         struct tevent_context *ev;
    3955           0 :         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           0 :         struct tevent_req *req;
    4006           0 :         struct netlogon_creds_cli_LogonGetDomainInfo_state *state;
    4007           0 :         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           0 :         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           0 :         struct tevent_req *req =
    4077           0 :                 tevent_req_callback_data(subreq,
    4078             :                 struct tevent_req);
    4079           0 :         struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
    4080           0 :                 tevent_req_data(req,
    4081             :                 struct netlogon_creds_cli_LogonGetDomainInfo_state);
    4082           0 :         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           0 :         struct tevent_req *req =
    4156           0 :                 tevent_req_callback_data(subreq,
    4157             :                 struct tevent_req);
    4158           0 :         struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
    4159           0 :                 tevent_req_data(req,
    4160             :                 struct netlogon_creds_cli_LogonGetDomainInfo_state);
    4161           0 :         NTSTATUS status;
    4162           0 :         NTSTATUS result;
    4163           0 :         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           0 :         struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
    4209           0 :                 tevent_req_data(req,
    4210             :                 struct netlogon_creds_cli_LogonGetDomainInfo_state);
    4211           0 :         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           0 :         struct tevent_context *ev;
    4235           0 :         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