libcli/auth/netlogon_creds_cli.c
authorStefan Metzmacher <metze@samba.org>
Thu, 18 Apr 2013 17:16:42 +0000 (19:16 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 30 Apr 2013 06:49:14 +0000 (08:49 +0200)
libcli/auth/netlogon_creds_cli.c [new file with mode: 0644]
libcli/auth/netlogon_creds_cli.h [new file with mode: 0644]
libcli/auth/wscript_build

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
new file mode 100644 (file)
index 0000000..085f734
--- /dev/null
@@ -0,0 +1,2010 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   module to store/fetch session keys for the schannel client
+
+   Copyright (C) Stefan Metzmacher 2013
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include <tevent.h>
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/dbwrap/dbwrap.h"
+#include "lib/dbwrap/dbwrap_rbt.h"
+#include "lib/util/util_tdb.h"
+#include "libcli/security/security.h"
+#include "../lib/param/param.h"
+#include "../libcli/auth/schannel.h"
+#include "../librpc/gen_ndr/ndr_schannel.h"
+#include "../librpc/gen_ndr/ndr_netlogon_c.h"
+#include "netlogon_creds_cli.h"
+
+struct netlogon_creds_cli_context {
+       struct {
+               const char *computer;
+               const char *account;
+               uint32_t proposed_flags;
+               uint32_t required_flags;
+               enum netr_SchannelType type;
+       } client;
+
+       struct {
+               const char *computer;
+               const char *netbios_domain;
+               uint32_t cached_flags;
+               bool try_validation6;
+               bool try_logon_ex;
+               bool try_logon_with;
+       } server;
+
+       struct {
+               const char *key_name;
+               TDB_DATA key_data;
+               struct db_context *ctx;
+               struct g_lock_ctx *g_ctx;
+       } db;
+};
+
+static NTSTATUS netlogon_creds_cli_context_common(
+                               const char *client_computer,
+                               const char *client_account,
+                               enum netr_SchannelType type,
+                               uint32_t proposed_flags,
+                               uint32_t required_flags,
+                               const char *server_computer,
+                               const char *server_netbios_domain,
+                               TALLOC_CTX *mem_ctx,
+                               struct netlogon_creds_cli_context **_context)
+{
+       struct netlogon_creds_cli_context *context = NULL;
+
+       *_context = NULL;
+
+       context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
+       if (context == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       context->client.computer = talloc_strdup(context, client_computer);
+       if (context->client.computer == NULL) {
+               talloc_free(context);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       context->client.account = talloc_strdup(context, client_account);
+       if (context->client.account == NULL) {
+               talloc_free(context);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       context->client.proposed_flags = proposed_flags;
+       context->client.required_flags = required_flags;
+       context->client.type = type;
+
+       context->server.computer = talloc_strdup(context, server_computer);
+       if (context->server.computer == NULL) {
+               talloc_free(context);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
+       if (context->server.netbios_domain == NULL) {
+               talloc_free(context);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       context->db.key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%s/%s]",
+                                            client_computer,
+                                            client_account,
+                                            server_computer,
+                                            server_netbios_domain);
+       if (context->db.key_name == NULL) {
+               talloc_free(context);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       context->db.key_data = string_term_tdb_data(context->db.key_name);
+
+       *_context = context;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
+                               const char *client_account,
+                               enum netr_SchannelType type,
+                               const char *server_computer,
+                               const char *server_netbios_domain,
+                               TALLOC_CTX *mem_ctx,
+                               struct netlogon_creds_cli_context **_context)
+{
+       static struct db_context *global_db = NULL;
+       char *fname = NULL;
+       NTSTATUS status;
+       struct netlogon_creds_cli_context *context = NULL;
+       const char *client_computer;
+       uint32_t proposed_flags;
+       uint32_t required_flags = 0;
+       bool reject_md5_servers = false;
+       bool require_strong_key = false;
+       int require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
+
+       *_context = NULL;
+
+       client_computer = lpcfg_netbios_name(lp_ctx);
+
+       //TODO: add lpcfp_reject_md5_servers()
+       reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
+                                            "__default__",
+                                            "reject md5 servers",
+                                            reject_md5_servers);
+       /*
+        * allow overwrite per domain
+        * reject md5 servers:<netbios_domain>
+        */
+       reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
+                                            "reject md5 servers",
+                                            server_netbios_domain,
+                                            reject_md5_servers);
+
+       //TODO: add lpcfp_require_strong_key()
+       require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
+                                            "__default__",
+                                            "require strong key",
+                                            require_strong_key);
+       /*
+        * allow overwrite per domain
+        * require strong key:<netbios_domain>
+        */
+       require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
+                                            "require strong key",
+                                            server_netbios_domain,
+                                            require_strong_key);
+
+       proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+       proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
+
+       if (reject_md5_servers) {
+               required_flags |= NETLOGON_NEG_SUPPORTS_AES;
+               required_flags |= NETLOGON_NEG_PASSWORD_SET2;
+               required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
+       }
+
+       if (require_strong_key) {
+               required_flags |= NETLOGON_NEG_STRONG_KEYS;
+               required_flags |= NETLOGON_NEG_ARCFOUR;
+               required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
+       }
+
+       if (require_sign_or_seal == true) {
+               required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
+       }
+
+       status = netlogon_creds_cli_context_common(client_account,
+                                                  client_computer,
+                                                  type,
+                                                  proposed_flags,
+                                                  required_flags,
+                                                  server_computer,
+                                                  server_netbios_domain,
+                                                  mem_ctx,
+                                                  &context);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (global_db != NULL) {
+               context->db.ctx = global_db;
+               *_context = context;
+               return NT_STATUS_OK;
+       }
+
+       fname = lpcfg_private_db_path(context, lp_ctx, "netlogon_creds_cli");
+       if (fname == NULL) {
+               talloc_free(context);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       global_db = dbwrap_local_open(talloc_autofree_context(), lp_ctx,
+                                     fname, 0,
+                                     TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
+                                     O_RDWR|O_CREAT,
+                                     0600, DBWRAP_LOCK_ORDER_2);
+       if (global_db == NULL) {
+               DEBUG(0,("netlogon_creds_cli_context_global: Failed to open %s - %s\n",
+                        fname, strerror(errno)));
+               talloc_free(context);
+               return NT_STATUS_NO_MEMORY;
+       }
+       TALLOC_FREE(fname);
+
+       context->db.ctx = global_db;
+       *_context = context;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_context_tmp(const char *client_account,
+                               const char *client_computer,
+                               enum netr_SchannelType type,
+                               uint32_t proposed_flags,
+                               uint32_t required_flags,
+                               const char *server_computer,
+                               const char *server_netbios_domain,
+                               TALLOC_CTX *mem_ctx,
+                               struct netlogon_creds_cli_context **_context)
+{
+       NTSTATUS status;
+       struct netlogon_creds_cli_context *context = NULL;
+
+       *_context = NULL;
+
+       status = netlogon_creds_cli_context_common(client_account,
+                                                client_computer,
+                                                type,
+                                                proposed_flags,
+                                                required_flags,
+                                                server_computer,
+                                                server_netbios_domain,
+                                                mem_ctx,
+                                                &context);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       context->db.ctx = db_open_rbt(context);
+       if (context->db.ctx == NULL) {
+               talloc_free(context);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       *_context = context;
+       return NT_STATUS_OK;
+}
+
+struct netlogon_creds_cli_fetch_state {
+       TALLOC_CTX *mem_ctx;
+       struct netlogon_creds_CredentialState *creds;
+       NTSTATUS status;
+};
+
+static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
+                                           void *private_data)
+{
+       struct netlogon_creds_cli_fetch_state *state =
+               (struct netlogon_creds_cli_fetch_state *)private_data;
+       enum ndr_err_code ndr_err;
+       DATA_BLOB blob;
+
+       state->creds = talloc_zero(state->mem_ctx,
+                                  struct netlogon_creds_CredentialState);
+       if (state->creds == NULL) {
+               state->status = NT_STATUS_NO_MEMORY;
+               return;
+       }
+
+       blob.data = data.dptr;
+       blob.length = data.dsize;
+
+       ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
+               (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               TALLOC_FREE(state->creds);
+               state->status = ndr_map_error2ntstatus(ndr_err);
+               return;
+       }
+
+       state->status = NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
+                               TALLOC_CTX *mem_ctx,
+                               struct netlogon_creds_CredentialState **_creds)
+{
+       NTSTATUS status;
+       struct netlogon_creds_cli_fetch_state fstate = {
+               .mem_ctx = mem_ctx,
+               .status = NT_STATUS_INTERNAL_ERROR,
+       };
+       static const struct netr_Credential zero_creds;
+
+       *_creds = NULL;
+
+       status = dbwrap_parse_record(context->db.ctx,
+                                    context->db.key_data,
+                                    netlogon_creds_cli_fetch_parser,
+                                    &fstate);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       status = fstate.status;
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /*
+        * mark it as invalid for step operations.
+        */
+       fstate.creds->sequence = 0;
+       fstate.creds->seed = zero_creds;
+       fstate.creds->client = zero_creds;
+       fstate.creds->server = zero_creds;
+
+       if (context->server.cached_flags == fstate.creds->negotiate_flags) {
+               *_creds = fstate.creds;
+               return NT_STATUS_OK;
+       }
+
+       context->server.cached_flags = fstate.creds->negotiate_flags;
+       context->server.try_validation6 = true;
+       context->server.try_logon_ex = true;
+       context->server.try_logon_with = true;
+
+       if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+               context->server.try_validation6 = false;
+               context->server.try_logon_ex = false;
+       }
+       if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
+               context->server.try_validation6 = false;
+       }
+
+       *_creds = fstate.creds;
+       return NT_STATUS_OK;
+}
+
+bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
+                       const struct netlogon_creds_CredentialState *creds1)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct netlogon_creds_CredentialState *creds2;
+       NTSTATUS status;
+
+       status = netlogon_creds_cli_get(context, frame, &creds2);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       if (creds1->negotiate_flags != creds2->negotiate_flags) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+       if (memcmp(creds1->session_key, creds2->session_key, 16) != 0) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       if (creds1->sequence != creds2->sequence) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       if (memcmp(&creds1->seed, &creds2->seed, sizeof(creds2->seed)) != 0) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       if (memcmp(&creds1->client, &creds2->client, sizeof(creds2->client)) != 0) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       if (memcmp(&creds1->server, &creds2->server, sizeof(creds2->server)) != 0) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       if (creds1->secure_channel_type != creds2->secure_channel_type) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       if (!strequal(creds1->computer_name, creds2->computer_name)) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       if (!strequal(creds1->account_name, creds2->account_name)) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       if (dom_sid_compare(creds1->sid, creds2->sid) != 0) {
+               TALLOC_FREE(frame);
+               return false;
+       }
+
+       TALLOC_FREE(frame);
+       return true;
+}
+
+NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
+                                 struct netlogon_creds_CredentialState **_creds)
+{
+       struct netlogon_creds_CredentialState *creds = *_creds;
+       NTSTATUS status;
+       enum ndr_err_code ndr_err;
+       DATA_BLOB blob;
+       TDB_DATA data;
+       static const struct netr_Credential zero_creds;
+       bool valid = false;
+
+       *_creds = NULL;
+
+       if (creds->sequence != 0) {
+               valid = true;
+       } else if (memcmp(&creds->seed, &zero_creds, sizeof(zero_creds)) != 0) {
+               valid = true;
+       } else if (memcmp(&creds->client, &zero_creds, sizeof(zero_creds)) != 0) {
+               valid = true;
+       } else if (memcmp(&creds->server, &zero_creds, sizeof(zero_creds)) != 0) {
+               valid = true;
+       }
+
+       if (!valid) {
+               /*
+                * this was the result of netlogon_creds_cli_get()
+                * which only gives a valid read only session key.
+                */
+               TALLOC_FREE(creds);
+               return NT_STATUS_INVALID_PAGE_PROTECTION;
+       }
+
+       ndr_err = ndr_push_struct_blob(&blob, creds, creds,
+               (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               TALLOC_FREE(creds);
+               status = ndr_map_error2ntstatus(ndr_err);
+               return status;
+       }
+
+       data.dptr = blob.data;
+       data.dsize = blob.length;
+
+       status = dbwrap_store(context->db.ctx,
+                             context->db.key_data,
+                             data, TDB_REPLACE);
+       TALLOC_FREE(creds);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
+                                  struct netlogon_creds_CredentialState **_creds)
+{
+       struct netlogon_creds_CredentialState *creds = *_creds;
+       NTSTATUS status;
+       static const struct netr_Credential zero_creds;
+       bool valid = false;
+
+       *_creds = NULL;
+
+       if (creds->sequence != 0) {
+               valid = true;
+       } else if (memcmp(&creds->seed, &zero_creds, sizeof(zero_creds)) != 0) {
+               valid = true;
+       } else if (memcmp(&creds->client, &zero_creds, sizeof(zero_creds)) != 0) {
+               valid = true;
+       } else if (memcmp(&creds->server, &zero_creds, sizeof(zero_creds)) != 0) {
+               valid = true;
+       }
+
+       if (!valid) {
+               /*
+                * this was the result of netlogon_creds_cli_get()
+                * which only gives a valid read only session key.
+                */
+               TALLOC_FREE(creds);
+               return NT_STATUS_INVALID_PAGE_PROTECTION;
+       }
+
+       status = dbwrap_delete(context->db.ctx,
+                              context->db.key_data);
+       TALLOC_FREE(creds);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       return NT_STATUS_OK;
+}
+
+struct netlogon_creds_cli_lock_state {
+       struct netlogon_creds_CredentialState *creds;
+};
+
+struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct netlogon_creds_cli_context *context)
+{
+       struct tevent_req *req;
+       struct netlogon_creds_cli_lock_state *state;
+       struct netlogon_creds_cli_fetch_state fstate = {
+               .status = NT_STATUS_INTERNAL_ERROR,
+       };
+       NTSTATUS status;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct netlogon_creds_cli_lock_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       fstate.mem_ctx = state;
+       status = dbwrap_parse_record(context->db.ctx,
+                                    context->db.key_data,
+                                    netlogon_creds_cli_fetch_parser,
+                                    &fstate);
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
+       status = fstate.status;
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
+
+       if (context->server.cached_flags == fstate.creds->negotiate_flags) {
+               state->creds = fstate.creds;
+               tevent_req_done(req);
+               return tevent_req_post(req, ev);
+       }
+
+       context->server.cached_flags = fstate.creds->negotiate_flags;
+       context->server.try_validation6 = true;
+       context->server.try_logon_ex = true;
+       context->server.try_logon_with = true;
+
+       if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+               context->server.try_validation6 = false;
+               context->server.try_logon_ex = false;
+       }
+       if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
+               context->server.try_validation6 = false;
+       }
+
+       state->creds = fstate.creds;
+       tevent_req_done(req);
+       return tevent_req_post(req, ev);
+}
+
+NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
+                       TALLOC_CTX *mem_ctx,
+                       struct netlogon_creds_CredentialState **creds)
+{
+       struct netlogon_creds_cli_lock_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_lock_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
+       }
+
+       *creds = talloc_move(mem_ctx, &state->creds);
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
+                       TALLOC_CTX *mem_ctx,
+                       struct netlogon_creds_CredentialState **creds)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       ev = samba_tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = netlogon_creds_cli_lock_send(frame, ev, context);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
+
+struct netlogon_creds_cli_auth_state {
+       struct tevent_context *ev;
+       struct netlogon_creds_cli_context *context;
+       struct dcerpc_binding_handle *binding_handle;
+       struct samr_Password current_nt_hash;
+       struct samr_Password previous_nt_hash;
+       struct samr_Password used_nt_hash;
+       char *srv_name_slash;
+       uint32_t current_flags;
+       struct netr_Credential client_challenge;
+       struct netr_Credential server_challenge;
+       struct netlogon_creds_CredentialState *creds;
+       struct netr_Credential client_credential;
+       struct netr_Credential server_credential;
+       uint32_t rid;
+       bool try_auth3;
+       bool try_auth2;
+       bool require_auth2;
+       bool try_previous_nt_hash;
+};
+
+static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
+
+struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b,
+                               struct samr_Password current_nt_hash,
+                               const struct samr_Password *previous_nt_hash)
+{
+       struct tevent_req *req;
+       struct netlogon_creds_cli_auth_state *state;
+       NTSTATUS status;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct netlogon_creds_cli_auth_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->ev = ev;
+       state->context = context;
+       state->binding_handle = b;
+       state->current_nt_hash = current_nt_hash;
+       if (previous_nt_hash != NULL) {
+               state->previous_nt_hash = *previous_nt_hash;
+               state->try_previous_nt_hash = true;
+       }
+
+       state->used_nt_hash = state->current_nt_hash;
+
+       if (context->client.required_flags & NETLOGON_NEG_SUPPORTS_AES) {
+               state->try_auth2 = true;
+               state->require_auth2 = true;
+       }
+
+       if (context->client.required_flags & NETLOGON_NEG_STRONG_KEYS) {
+               state->try_auth2 = true;
+               state->require_auth2 = true;
+       }
+
+       state->current_flags = context->client.proposed_flags;
+
+       if (state->current_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
+               state->try_auth3 = true;
+               state->try_auth2 = true;
+       }
+
+       state->srv_name_slash = talloc_asprintf(state, "\\%s",
+                                               context->server.computer);
+       if (tevent_req_nomem(state->srv_name_slash, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       status = dbwrap_delete(state->context->db.ctx,
+                              state->context->db.key_data);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+               status = NT_STATUS_OK;
+       }
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
+
+       netlogon_creds_cli_auth_challenge_start(req);
+
+       if (!tevent_req_is_in_progress(req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       return req;
+}
+
+static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
+{
+       struct netlogon_creds_cli_auth_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_auth_state);
+       struct tevent_req *subreq;
+
+       generate_random_buffer(state->client_challenge.data,
+                              sizeof(state->client_challenge.data));
+
+       subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
+                                               state->binding_handle,
+                                               state->srv_name_slash,
+                                               state->context->client.computer,
+                                               &state->client_challenge,
+                                               &state->server_challenge);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq,
+                               netlogon_creds_cli_auth_challenge_done,
+                               req);
+}
+
+static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct netlogon_creds_cli_auth_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_auth_state);
+       NTSTATUS status;
+       NTSTATUS result;
+
+       status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       if (tevent_req_nterror(req, result)) {
+               return;
+       }
+
+       /* Calculate the session key and client credentials */
+
+       state->creds = netlogon_creds_client_init(state,
+                                                 state->context->client.account,
+                                                 state->context->client.computer,
+                                                 &state->client_challenge,
+                                                 &state->server_challenge,
+                                                 &state->used_nt_hash,
+                                                 &state->client_credential,
+                                                 state->current_flags);
+       if (tevent_req_nomem(state->creds, req)) {
+               return;
+       }
+
+       if (state->try_auth3) {
+               subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
+                                               state->binding_handle,
+                                               state->srv_name_slash,
+                                               state->context->client.account,
+                                               state->context->client.type,
+                                               state->context->client.computer,
+                                               &state->client_credential,
+                                               &state->server_credential,
+                                               &state->creds->negotiate_flags,
+                                               &state->rid);
+               if (tevent_req_nomem(subreq, req)) {
+                       return;
+               }
+       } else if (state->try_auth2) {
+               state->rid = 0;
+
+               subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
+                                               state->binding_handle,
+                                               state->srv_name_slash,
+                                               state->context->client.account,
+                                               state->context->client.type,
+                                               state->context->client.computer,
+                                               &state->client_credential,
+                                               &state->server_credential,
+                                               &state->creds->negotiate_flags);
+               if (tevent_req_nomem(subreq, req)) {
+                       return;
+               }
+       } else {
+               state->rid = 0;
+               /*
+                * keep old samba versions happy.
+                */
+               state->creds->negotiate_flags = NETLOGON_NEG_AUTHENTICATED_RPC;
+
+               subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
+                                               state->binding_handle,
+                                               state->srv_name_slash,
+                                               state->context->client.account,
+                                               state->context->client.type,
+                                               state->context->client.computer,
+                                               &state->client_credential,
+                                               &state->server_credential);
+               if (tevent_req_nomem(subreq, req)) {
+                       return;
+               }
+       }
+       tevent_req_set_callback(subreq,
+                               netlogon_creds_cli_auth_srvauth_done,
+                               req);
+}
+
+static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct netlogon_creds_cli_auth_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_auth_state);
+       NTSTATUS status;
+       NTSTATUS result;
+       bool ok;
+       enum ndr_err_code ndr_err;
+       DATA_BLOB blob;
+       TDB_DATA data;
+       uint32_t tmp_flags;
+
+       if (state->try_auth3) {
+               status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
+                                                             &result);
+               TALLOC_FREE(subreq);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+                       state->try_auth3 = false;
+                       TALLOC_FREE(state->creds);
+                       netlogon_creds_cli_auth_challenge_start(req);
+                       return;
+               }
+               if (tevent_req_nterror(req, status)) {
+                       return;
+               }
+       } else if (state->try_auth2) {
+               status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
+                                                             &result);
+               TALLOC_FREE(subreq);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+                       state->try_auth2 = false;
+                       if (state->require_auth2) {
+                               status = NT_STATUS_DOWNGRADE_DETECTED;
+                               tevent_req_nterror(req, status);
+                               return;
+                       }
+                       TALLOC_FREE(state->creds);
+                       netlogon_creds_cli_auth_challenge_start(req);
+                       return;
+               }
+               if (tevent_req_nterror(req, status)) {
+                       return;
+               }
+       } else {
+               status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
+                                                            &result);
+               TALLOC_FREE(subreq);
+               if (tevent_req_nterror(req, status)) {
+                       return;
+               }
+       }
+
+       tmp_flags = state->creds->negotiate_flags;
+       tmp_flags &= state->context->client.required_flags;
+       if (tmp_flags != state->context->client.required_flags) {
+               if (NT_STATUS_IS_OK(result)) {
+                       tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
+                       return;
+               }
+               tevent_req_nterror(req, result);
+               return;
+       }
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
+               tmp_flags = state->context->client.proposed_flags;
+               if (state->current_flags != tmp_flags) {
+                       if (!state->try_previous_nt_hash) {
+                               /*
+                                * we already retried, giving up...
+                                */
+                               tevent_req_nterror(req, result);
+                               return;
+                       }
+
+                       /*
+                        * lets retry with the old nt hash.
+                        */
+                       state->used_nt_hash = state->previous_nt_hash;
+                       state->try_previous_nt_hash = false;
+                       state->current_flags = tmp_flags;
+                       TALLOC_FREE(state->creds);
+                       netlogon_creds_cli_auth_challenge_start(req);
+                       return;
+               }
+
+               /*
+                * lets retry with the negotiated flags
+                */
+               state->current_flags = state->creds->negotiate_flags;
+               TALLOC_FREE(state->creds);
+               netlogon_creds_cli_auth_challenge_start(req);
+               return;
+       }
+
+       ok = netlogon_creds_client_check(state->creds,
+                                        &state->server_credential);
+       if (!ok) {
+               tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+               return;
+       }
+
+       ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
+               (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               status = ndr_map_error2ntstatus(ndr_err);
+               tevent_req_nterror(req, status);
+               return;
+       }
+
+       data.dptr = blob.data;
+       data.dsize = blob.length;
+
+       status = dbwrap_store(state->context->db.ctx,
+                             state->context->db.key_data,
+                             data, TDB_REPLACE);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req)
+{
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
+       }
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
+                                struct dcerpc_binding_handle *b,
+                                struct samr_Password current_nt_hash,
+                                const struct samr_Password *previous_nt_hash)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       ev = samba_tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = netlogon_creds_cli_auth_send(frame, ev, context, b,
+                                          current_nt_hash,
+                                          previous_nt_hash);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = netlogon_creds_cli_auth_recv(req);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
+
+struct netlogon_creds_cli_check_state {
+       struct tevent_context *ev;
+       struct netlogon_creds_cli_context *context;
+       struct dcerpc_binding_handle *binding_handle;
+
+       char *srv_name_slash;
+       char *cli_name_slash;
+
+       union netr_Capabilities caps;
+
+       struct netlogon_creds_CredentialState *creds;
+       struct netlogon_creds_CredentialState tmp_creds;
+       struct netr_Authenticator req_auth;
+       struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
+                                                    NTSTATUS status);
+static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b)
+{
+       struct tevent_req *req;
+       struct netlogon_creds_cli_check_state *state;
+       struct tevent_req *subreq;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct netlogon_creds_cli_check_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->ev = ev;
+       state->context = context;
+       state->binding_handle = b;
+
+       state->srv_name_slash = talloc_asprintf(state, "\\%s",
+                                               context->server.computer);
+       if (tevent_req_nomem(state->srv_name_slash, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       state->cli_name_slash = talloc_asprintf(state, "\\%s",
+                                               context->client.computer);
+       if (tevent_req_nomem(state->cli_name_slash, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       /*
+        * TODO
+        * verify DCERPC_AUTH_TYPE_SCHANNEL
+        */
+
+       subreq = netlogon_creds_cli_lock_send(state, state->ev,
+                                             state->context);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_set_callback(subreq,
+                               netlogon_creds_cli_check_locked,
+                               req);
+
+       return req;
+}
+
+static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
+                                            NTSTATUS status)
+{
+       struct netlogon_creds_cli_check_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_check_state);
+
+       if (state->creds == NULL) {
+               return;
+       }
+
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+           !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED)) {
+               TALLOC_FREE(state->creds);
+               return;
+       }
+
+       netlogon_creds_cli_delete(state->context, &state->creds);
+}
+
+static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct netlogon_creds_cli_check_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_check_state);
+       NTSTATUS status;
+
+       status = netlogon_creds_cli_lock_recv(subreq, state,
+                                             &state->creds);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       /*
+        * we defer all callbacks in order to cleanup
+        * the database record.
+        */
+       tevent_req_defer_callback(req, state->ev);
+
+       state->tmp_creds = *state->creds;
+       netlogon_creds_client_authenticator(&state->tmp_creds,
+                                           &state->req_auth);
+       ZERO_STRUCT(state->rep_auth);
+
+       subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
+                                               state->binding_handle,
+                                               state->srv_name_slash,
+                                               state->cli_name_slash,
+                                               &state->req_auth,
+                                               &state->rep_auth,
+                                               1,
+                                               &state->caps);
+       if (tevent_req_nomem(subreq, req)) {
+               status = NT_STATUS_NO_MEMORY;
+               netlogon_creds_cli_check_cleanup(req, status);
+               return;
+       }
+       tevent_req_set_callback(subreq,
+                               netlogon_creds_cli_check_caps,
+                               req);
+}
+
+static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct netlogon_creds_cli_check_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_check_state);
+       NTSTATUS status;
+       NTSTATUS result;
+       bool ok;
+
+       status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
+                                                        &result);
+       TALLOC_FREE(subreq);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+               status = NT_STATUS_OK;
+               result = NT_STATUS_NOT_IMPLEMENTED;
+       }
+       if (tevent_req_nterror(req, status)) {
+               netlogon_creds_cli_check_cleanup(req, status);
+               return;
+       }
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
+               if (tevent_req_nterror(req, result)) {
+                       netlogon_creds_cli_check_cleanup(req, result);
+                       return;
+               }
+       }
+
+       ok = netlogon_creds_client_check(&state->tmp_creds,
+                                        &state->rep_auth.cred);
+       if (!ok) {
+               status = NT_STATUS_ACCESS_DENIED;
+               tevent_req_nterror(req, status);
+               netlogon_creds_cli_check_cleanup(req, status);
+               return;
+       }
+
+       if (tevent_req_nterror(req, result)) {
+               netlogon_creds_cli_check_cleanup(req, result);
+               return;
+       }
+
+       if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
+               status = NT_STATUS_DOWNGRADE_DETECTED;
+               tevent_req_nterror(req, status);
+               netlogon_creds_cli_check_cleanup(req, status);
+               return;
+       }
+
+       if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
+               status = NT_STATUS_DOWNGRADE_DETECTED;
+               tevent_req_nterror(req, status);
+               netlogon_creds_cli_check_cleanup(req, status);
+               return;
+       }
+
+       *state->creds = state->tmp_creds;
+       status = netlogon_creds_cli_store(state->context,
+                                         &state->creds);
+       if (tevent_req_nterror(req, status)) {
+               netlogon_creds_cli_check_cleanup(req, status);
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
+{
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               netlogon_creds_cli_check_cleanup(req, status);
+               tevent_req_received(req);
+               return status;
+       }
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
+                                 struct dcerpc_binding_handle *b)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       ev = samba_tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = netlogon_creds_cli_check_send(frame, ev, context, b);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = netlogon_creds_cli_check_recv(req);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
+
+struct netlogon_creds_cli_ServerPasswordSet_state {
+       struct tevent_context *ev;
+       struct netlogon_creds_cli_context *context;
+       struct dcerpc_binding_handle *binding_handle;
+       uint32_t old_timeout;
+
+       const char *new_password;
+
+       char *srv_name_slash;
+
+       struct netr_CryptPassword crypt_password;
+       struct samr_Password samr_password;
+
+       struct netlogon_creds_CredentialState *creds;
+       struct netlogon_creds_CredentialState tmp_creds;
+       struct netr_Authenticator req_auth;
+       struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
+                                                    NTSTATUS status);
+static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b,
+                               const char *new_password)
+{
+       struct tevent_req *req;
+       struct netlogon_creds_cli_ServerPasswordSet_state *state;
+       struct tevent_req *subreq;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct netlogon_creds_cli_ServerPasswordSet_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->ev = ev;
+       state->context = context;
+       state->binding_handle = b;
+
+       state->new_password = talloc_strdup(state, new_password);
+       if (tevent_req_nomem(state->new_password, req)) {
+               return tevent_req_post(req, ev);
+       }
+       talloc_set_name_const(state->new_password, "<new_password>");
+
+       state->srv_name_slash = talloc_asprintf(state, "\\%s",
+                                               context->server.computer);
+       if (tevent_req_nomem(state->srv_name_slash, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       /*
+        * TODO
+        * verify DCERPC_AUTH_TYPE_SCHANNEL
+        */
+
+       subreq = netlogon_creds_cli_lock_send(state, state->ev,
+                                             state->context);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_set_callback(subreq,
+                               netlogon_creds_cli_ServerPasswordSet_locked,
+                               req);
+
+       return req;
+}
+
+static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
+                                                        NTSTATUS status)
+{
+       struct netlogon_creds_cli_ServerPasswordSet_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_ServerPasswordSet_state);
+
+       if (state->creds == NULL) {
+               return;
+       }
+
+       dcerpc_binding_handle_set_timeout(state->binding_handle,
+                                         state->old_timeout);
+
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+               TALLOC_FREE(state->creds);
+               return;
+       }
+
+       netlogon_creds_cli_delete(state->context, &state->creds);
+}
+
+static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct netlogon_creds_cli_ServerPasswordSet_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_ServerPasswordSet_state);
+       NTSTATUS status;
+
+       status = netlogon_creds_cli_lock_recv(subreq, state,
+                                             &state->creds);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       state->old_timeout = dcerpc_binding_handle_set_timeout(
+                               state->binding_handle, 600000);
+
+       /*
+        * we defer all callbacks in order to cleanup
+        * the database record.
+        */
+       tevent_req_defer_callback(req, state->ev);
+
+       state->tmp_creds = *state->creds;
+       netlogon_creds_client_authenticator(&state->tmp_creds,
+                                           &state->req_auth);
+       ZERO_STRUCT(state->rep_auth);
+
+       if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
+               struct samr_CryptPassword password_buf;
+
+               encode_pw_buffer(password_buf.data,
+                                state->new_password, STR_UNICODE);
+
+               if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+                       netlogon_creds_aes_encrypt(&state->tmp_creds,
+                                                  password_buf.data, 516);
+               } else {
+                       netlogon_creds_arcfour_crypt(&state->tmp_creds,
+                                                    password_buf.data, 516);
+               }
+
+               memcpy(state->crypt_password.data, password_buf.data, 512);
+               state->crypt_password.length = IVAL(password_buf.data, 512);
+               ZERO_STRUCT(password_buf);
+
+               subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
+                                       state->binding_handle,
+                                       state->srv_name_slash,
+                                       state->tmp_creds.account_name,
+                                       /* TODO: state->tmp_creds.secure_channel_type, */
+                                       state->context->client.type,
+                                       state->tmp_creds.computer_name,
+                                       &state->req_auth,
+                                       &state->rep_auth,
+                                       &state->crypt_password);
+               if (tevent_req_nomem(subreq, req)) {
+                       status = NT_STATUS_NO_MEMORY;
+                       netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+                       return;
+               }
+       } else {
+               E_md4hash(state->new_password, state->samr_password.hash);
+               netlogon_creds_des_encrypt(&state->tmp_creds,
+                                          &state->samr_password);
+
+               subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
+                                       state->binding_handle,
+                                       state->srv_name_slash,
+                                       state->tmp_creds.account_name,
+                                       state->tmp_creds.secure_channel_type,
+                                       state->tmp_creds.computer_name,
+                                       &state->req_auth,
+                                       &state->rep_auth,
+                                       &state->samr_password);
+               if (tevent_req_nomem(subreq, req)) {
+                       status = NT_STATUS_NO_MEMORY;
+                       netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+                       return;
+               }
+       }
+
+       tevent_req_set_callback(subreq,
+                               netlogon_creds_cli_ServerPasswordSet_done,
+                               req);
+}
+
+static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct netlogon_creds_cli_ServerPasswordSet_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_ServerPasswordSet_state);
+       NTSTATUS status;
+       NTSTATUS result;
+       bool ok;
+
+       if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
+               status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
+                                                            &result);
+               TALLOC_FREE(subreq);
+               if (tevent_req_nterror(req, status)) {
+                       netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+                       return;
+               }
+       } else {
+               status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
+                                                           &result);
+               TALLOC_FREE(subreq);
+               if (tevent_req_nterror(req, status)) {
+                       netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+                       return;
+               }
+       }
+
+       ok = netlogon_creds_client_check(&state->tmp_creds,
+                                        &state->rep_auth.cred);
+       if (!ok) {
+               status = NT_STATUS_ACCESS_DENIED;
+               tevent_req_nterror(req, status);
+               netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+               return;
+       }
+
+       if (tevent_req_nterror(req, result)) {
+               netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
+               return;
+       }
+
+       dcerpc_binding_handle_set_timeout(state->binding_handle,
+                                         state->old_timeout);
+
+       *state->creds = state->tmp_creds;
+       status = netlogon_creds_cli_store(state->context,
+                                         &state->creds);
+       if (tevent_req_nterror(req, status)) {
+               netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
+{
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+               tevent_req_received(req);
+               return status;
+       }
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_ServerPasswordSet(
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b,
+                               const char *new_password)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       ev = samba_tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
+                                                       new_password);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = netlogon_creds_cli_ServerPasswordSet_recv(req);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
+
+struct netlogon_creds_cli_LogonSamLogon_state {
+       struct tevent_context *ev;
+       struct netlogon_creds_cli_context *context;
+       struct dcerpc_binding_handle *binding_handle;
+
+       char *srv_name_slash;
+       char *cli_name_slash;
+
+       enum netr_LogonInfoClass logon_level;
+       const union netr_LogonLevel *const_logon;
+       union netr_LogonLevel *logon;
+       uint32_t flags;
+
+       uint16_t validation_level;
+       union netr_Validation *validation;
+       uint8_t authoritative;
+
+       /*
+        * do we need encryption at the application layer?
+        */
+       bool user_encrypt;
+
+       /*
+        * the read only credentials before we started the operation
+        */
+       struct netlogon_creds_CredentialState *ro_creds;
+
+       struct netlogon_creds_CredentialState *lk_creds;
+
+       struct netlogon_creds_CredentialState tmp_creds;
+       struct netr_Authenticator req_auth;
+       struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
+static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
+                                                    NTSTATUS status);
+
+struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b,
+                               enum netr_LogonInfoClass logon_level,
+                               const union netr_LogonLevel *logon,
+                               uint32_t flags)
+{
+       struct tevent_req *req;
+       struct netlogon_creds_cli_LogonSamLogon_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct netlogon_creds_cli_LogonSamLogon_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       state->ev = ev;
+       state->context = context;
+       state->binding_handle = b;
+
+       state->logon_level = logon_level;
+       state->const_logon = logon;
+       state->flags = flags;
+
+       state->srv_name_slash = talloc_asprintf(state, "\\%s",
+                                               context->server.computer);
+       if (tevent_req_nomem(state->srv_name_slash, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       state->cli_name_slash = talloc_asprintf(state, "\\%s",
+                                               context->client.computer);
+       if (tevent_req_nomem(state->cli_name_slash, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       switch (logon_level) {
+       case NetlogonInteractiveInformation:
+       case NetlogonInteractiveTransitiveInformation:
+       case NetlogonServiceInformation:
+       case NetlogonServiceTransitiveInformation:
+       case NetlogonGenericInformation:
+               state->user_encrypt = true;
+               break;
+
+       case NetlogonNetworkInformation:
+       case NetlogonNetworkTransitiveInformation:
+               break;
+       }
+
+       state->validation = talloc_zero(state, union netr_Validation);
+       if (tevent_req_nomem(state->validation, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       /*
+        * TODO
+        * verify DCERPC_AUTH_TYPE_SCHANNEL
+        * for try_logon_ex.
+        *
+        * and DCERPC_AUTH_LEVEL_PRIVACY for
+        * try_validation6
+        */
+
+       netlogon_creds_cli_LogonSamLogon_start(req);
+
+       if (!tevent_req_is_in_progress(req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       /*
+        * we defer all callbacks in order to cleanup
+        * the database record.
+        */
+       tevent_req_defer_callback(req, state->ev);
+       return req;
+}
+
+static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
+                                                    NTSTATUS status)
+{
+       struct netlogon_creds_cli_LogonSamLogon_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_LogonSamLogon_state);
+
+       if (state->lk_creds == NULL) {
+               return;
+       }
+
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+               TALLOC_FREE(state->lk_creds);
+               return;
+       }
+
+       netlogon_creds_cli_delete(state->context, &state->lk_creds);
+}
+
+static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
+{
+       struct netlogon_creds_cli_LogonSamLogon_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_LogonSamLogon_state);
+       struct tevent_req *subreq;
+       NTSTATUS status;
+
+       TALLOC_FREE(state->ro_creds);
+       TALLOC_FREE(state->logon);
+
+       if (state->context->server.try_logon_ex) {
+               if (state->context->server.try_validation6) {
+                       state->validation_level = 6;
+               } else {
+                       state->validation_level = 3;
+                       state->user_encrypt = true;
+               }
+
+               state->logon = netlogon_creds_shallow_copy_logon(state,
+                                                       state->logon_level,
+                                                       state->const_logon);
+               if (tevent_req_nomem(state->logon, req)) {
+                       status = NT_STATUS_NO_MEMORY;
+                       netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+                       return;
+               }
+
+               if (state->user_encrypt) {
+                       status = netlogon_creds_cli_get(state->context,
+                                                       state,
+                                                       &state->ro_creds);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               status = NT_STATUS_ACCESS_DENIED;
+                               tevent_req_nterror(req, status);
+                               netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+                               return;
+                       }
+
+                       netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
+                                                             state->logon_level,
+                                                             state->logon);
+               }
+
+               subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
+                                               state->binding_handle,
+                                               state->srv_name_slash,
+                                               state->cli_name_slash,
+                                               state->logon_level,
+                                               state->logon,
+                                               state->validation_level,
+                                               state->validation,
+                                               &state->authoritative,
+                                               &state->flags);
+               if (tevent_req_nomem(subreq, req)) {
+                       status = NT_STATUS_NO_MEMORY;
+                       netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+                       return;
+               }
+               tevent_req_set_callback(subreq,
+                                       netlogon_creds_cli_LogonSamLogon_done,
+                                       req);
+               return;
+       }
+
+       if (state->lk_creds == NULL) {
+               subreq = netlogon_creds_cli_lock_send(state, state->ev,
+                                                     state->context);
+               if (tevent_req_nomem(subreq, req)) {
+                       status = NT_STATUS_NO_MEMORY;
+                       netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+                       return;
+               }
+               tevent_req_set_callback(subreq,
+                                       netlogon_creds_cli_LogonSamLogon_done,
+                                       req);
+               return;
+       }
+
+       state->tmp_creds = *state->lk_creds;
+       netlogon_creds_client_authenticator(&state->tmp_creds,
+                                           &state->req_auth);
+       ZERO_STRUCT(state->rep_auth);
+
+       state->logon = netlogon_creds_shallow_copy_logon(state,
+                                               state->logon_level,
+                                               state->const_logon);
+       if (tevent_req_nomem(state->logon, req)) {
+               status = NT_STATUS_NO_MEMORY;
+               netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+               return;
+       }
+
+       netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
+                                             state->logon_level,
+                                             state->logon);
+
+       state->validation_level = 3;
+
+       if (state->context->server.try_logon_with) {
+               subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
+                                               state->binding_handle,
+                                               state->srv_name_slash,
+                                               state->cli_name_slash,
+                                               &state->req_auth,
+                                               &state->rep_auth,
+                                               state->logon_level,
+                                               state->logon,
+                                               state->validation_level,
+                                               state->validation,
+                                               &state->authoritative,
+                                               &state->flags);
+               if (tevent_req_nomem(subreq, req)) {
+                       status = NT_STATUS_NO_MEMORY;
+                       netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+                       return;
+               }
+       } else {
+               state->flags = 0;
+
+               subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
+                                               state->binding_handle,
+                                               state->srv_name_slash,
+                                               state->cli_name_slash,
+                                               &state->req_auth,
+                                               &state->rep_auth,
+                                               state->logon_level,
+                                               state->logon,
+                                               state->validation_level,
+                                               state->validation,
+                                               &state->authoritative);
+               if (tevent_req_nomem(subreq, req)) {
+                       status = NT_STATUS_NO_MEMORY;
+                       netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+                       return;
+               }
+       }
+
+       tevent_req_set_callback(subreq,
+                               netlogon_creds_cli_LogonSamLogon_done,
+                               req);
+}
+
+static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+       struct netlogon_creds_cli_LogonSamLogon_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_LogonSamLogon_state);
+       NTSTATUS status;
+       NTSTATUS result;
+       bool ok;
+
+       if (state->context->server.try_logon_ex) {
+               status = dcerpc_netr_LogonSamLogonEx_recv(subreq, state,
+                                                         &result);
+               TALLOC_FREE(subreq);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+                       state->context->server.try_validation6 = false;
+                       state->context->server.try_logon_ex = false;
+                       netlogon_creds_cli_LogonSamLogon_start(req);
+                       return;
+               }
+               if (tevent_req_nterror(req, status)) {
+                       netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+                       return;
+               }
+
+               if ((state->validation_level == 6) &&
+                   (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
+                    NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
+                    NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
+               {
+                       state->context->server.try_validation6 = false;
+                       netlogon_creds_cli_LogonSamLogon_start(req);
+                       return;
+               }
+
+               if (tevent_req_nterror(req, result)) {
+                       netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
+                       return;
+               }
+
+               if (state->ro_creds == NULL) {
+                       tevent_req_done(req);
+                       return;
+               }
+
+               ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
+               if (!ok) {
+                       status = NT_STATUS_ACCESS_DENIED;
+                       tevent_req_nterror(req, status);
+                       netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+                       return;
+               }
+
+               netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
+                                                       state->validation_level,
+                                                       state->validation);
+
+               tevent_req_done(req);
+               return;
+       }
+
+       if (state->lk_creds == NULL) {
+               status = netlogon_creds_cli_lock_recv(subreq, state,
+                                                     &state->lk_creds);
+               TALLOC_FREE(subreq);
+               if (tevent_req_nterror(req, status)) {
+                       netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+                       return;
+               }
+
+               netlogon_creds_cli_LogonSamLogon_start(req);
+               return;
+       }
+
+       if (state->context->server.try_logon_with) {
+               status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq, state,
+                                                                &result);
+               TALLOC_FREE(subreq);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+                       state->context->server.try_logon_with = false;
+                       netlogon_creds_cli_LogonSamLogon_start(req);
+                       return;
+               }
+               if (tevent_req_nterror(req, status)) {
+                       netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+                       return;
+               }
+       } else {
+               status = dcerpc_netr_LogonSamLogon_recv(subreq, state,
+                                                       &result);
+               TALLOC_FREE(subreq);
+               if (tevent_req_nterror(req, status)) {
+                       netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+                       return;
+               }
+       }
+
+       ok = netlogon_creds_client_check(&state->tmp_creds,
+                                        &state->rep_auth.cred);
+       if (!ok) {
+               status = NT_STATUS_ACCESS_DENIED;
+               tevent_req_nterror(req, status);
+               netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+               return;
+       }
+
+       *state->lk_creds = state->tmp_creds;
+       status = netlogon_creds_cli_store(state->context,
+                                         &state->lk_creds);
+       if (tevent_req_nterror(req, status)) {
+               netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+               return;
+       }
+
+       if (tevent_req_nterror(req, result)) {
+               netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
+               return;
+       }
+
+       netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
+                                               state->validation_level,
+                                               state->validation);
+
+       tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
+                                       TALLOC_CTX *mem_ctx,
+                                       uint16_t *validation_level,
+                                       union netr_Validation **validation,
+                                       uint8_t *authoritative,
+                                       uint32_t *flags)
+{
+       struct netlogon_creds_cli_LogonSamLogon_state *state =
+               tevent_req_data(req,
+               struct netlogon_creds_cli_LogonSamLogon_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+               tevent_req_received(req);
+               return status;
+       }
+
+       *validation_level = state->validation_level;
+       *validation = talloc_move(mem_ctx, &state->validation);
+       *authoritative = state->authoritative;
+       *flags = state->flags;
+
+       tevent_req_received(req);
+       return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_LogonSamLogon(
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b,
+                               enum netr_LogonInfoClass logon_level,
+                               const union netr_LogonLevel *logon,
+                               TALLOC_CTX *mem_ctx,
+                               uint16_t *validation_level,
+                               union netr_Validation **validation,
+                               uint8_t *authoritative,
+                               uint32_t *flags)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       ev = samba_tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
+                                                   logon_level, logon,
+                                                   *flags);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
+                                                      validation_level,
+                                                      validation,
+                                                      authoritative,
+                                                      flags);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
new file mode 100644 (file)
index 0000000..25848c3
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   module to store/fetch session keys for the schannel client
+
+   Copyright (C) Stefan Metzmacher 2013
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef NETLOGON_CREDS_CLI_H
+#define NETLOGON_CREDS_CLI_H
+
+struct netlogon_creds_cli_context;
+
+NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
+                               const char *client_account,
+                               enum netr_SchannelType type,
+                               const char *server_computer,
+                               const char *server_netbios_domain,
+                               TALLOC_CTX *mem_ctx,
+                               struct netlogon_creds_cli_context **_context);
+NTSTATUS netlogon_creds_cli_context_tmp(const char *client_account,
+                               const char *client_computer,
+                               enum netr_SchannelType type,
+                               uint32_t proposed_flags,
+                               uint32_t required_flags,
+                               const char *server_computer,
+                               const char *server_netbios_domain,
+                               TALLOC_CTX *mem_ctx,
+                               struct netlogon_creds_cli_context **_context);
+
+NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
+                               TALLOC_CTX *mem_ctx,
+                               struct netlogon_creds_CredentialState **_creds);
+bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
+                       const struct netlogon_creds_CredentialState *creds1);
+
+NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
+                                 struct netlogon_creds_CredentialState **_creds);
+NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
+                                  struct netlogon_creds_CredentialState **_creds);
+
+struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct netlogon_creds_cli_context *context);
+NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
+                       TALLOC_CTX *mem_ctx,
+                       struct netlogon_creds_CredentialState **creds);
+NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
+                       TALLOC_CTX *mem_ctx,
+                       struct netlogon_creds_CredentialState **creds);
+
+struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b,
+                               struct samr_Password current_nt_hash,
+                               const struct samr_Password *previous_nt_hash);
+NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req);
+NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
+                                struct dcerpc_binding_handle *b,
+                                struct samr_Password current_nt_hash,
+                                const struct samr_Password *previous_nt_hash);
+
+struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b);
+NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req);
+NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
+                                 struct dcerpc_binding_handle *b);
+
+struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b,
+                               const char *new_password);
+NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req);
+NTSTATUS netlogon_creds_cli_ServerPasswordSet(
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b,
+                               const char *new_password);
+
+struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev,
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b,
+                               enum netr_LogonInfoClass logon_level,
+                               const union netr_LogonLevel *logon,
+                               uint32_t flags);
+NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
+                                       TALLOC_CTX *mem_ctx,
+                                       uint16_t *validation_level,
+                                       union netr_Validation **validation,
+                                       uint8_t *authoritative,
+                                       uint32_t *flags);
+NTSTATUS netlogon_creds_cli_LogonSamLogon(
+                               struct netlogon_creds_cli_context *context,
+                               struct dcerpc_binding_handle *b,
+                               enum netr_LogonInfoClass logon_level,
+                               const union netr_LogonLevel *logon,
+                               TALLOC_CTX *mem_ctx,
+                               uint16_t *validation_level,
+                               union netr_Validation **validation,
+                               uint8_t *authoritative,
+                               uint32_t *flags);
+
+#endif /* NETLOGON_CREDS_CLI_H */
index df23058f6e74a3e80e1d0900a73e39fdd8023371..b4d88741cd1a04a74c17f124de6881df03f6751c 100755 (executable)
@@ -24,8 +24,8 @@ bld.SAMBA_SUBSYSTEM('LIBCLI_AUTH',
 
 
 bld.SAMBA_SUBSYSTEM('COMMON_SCHANNEL',
-       source='schannel_state_tdb.c schannel_sign.c',
-       deps='dbwrap util_tdb samba-hostconfig NDR_NETLOGON'
+       source='schannel_state_tdb.c schannel_sign.c netlogon_creds_cli.c',
+       deps='dbwrap util_tdb tevent-util samba-hostconfig RPC_NDR_NETLOGON NDR_NETLOGON'
        )