LCOV - code coverage report
Current view: top level - libcli/auth - netlogon_creds_cli.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 704 1818 38.7 %
Date: 2021-09-23 10:06:22 Functions: 43 80 53.8 %

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

Generated by: LCOV version 1.13