1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-31 17:18:04 +03:00

netlogon: Implement SendToSam along with its winbind forwarding

This allows you to forward bad password count resets to 0. Currently,
there is a missing access check for the RODC to ensure it only applies
to cached users (msDS-Allowed-Password-Replication-Group).

(further patches still need to address forcing a RWDC contact)

Signed-off-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
Garming Sam 2017-04-11 15:51:50 +12:00 committed by Andrew Bartlett
parent 8ae968193b
commit fd29e28d52
12 changed files with 571 additions and 15 deletions

View File

@ -31,6 +31,7 @@
#include "../libcli/auth/schannel.h"
#include "../librpc/gen_ndr/ndr_schannel.h"
#include "../librpc/gen_ndr/ndr_netlogon_c.h"
#include "../librpc/gen_ndr/ndr_netlogon.h"
#include "../librpc/gen_ndr/server_id.h"
#include "netlogon_creds_cli.h"
#include "source3/include/messages.h"
@ -3415,3 +3416,262 @@ NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
TALLOC_FREE(frame);
return status;
}
struct netlogon_creds_cli_SendToSam_state {
struct tevent_context *ev;
struct netlogon_creds_cli_context *context;
struct dcerpc_binding_handle *binding_handle;
char *srv_name_slash;
enum dcerpc_AuthType auth_type;
enum dcerpc_AuthLevel auth_level;
DATA_BLOB opaque;
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_SendToSam_cleanup(struct tevent_req *req,
NTSTATUS status);
static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct netlogon_creds_cli_context *context,
struct dcerpc_binding_handle *b,
struct netr_SendToSamBase *message)
{
struct tevent_req *req;
struct netlogon_creds_cli_SendToSam_state *state;
struct tevent_req *subreq;
enum ndr_err_code ndr_err;
req = tevent_req_create(mem_ctx, &state,
struct netlogon_creds_cli_SendToSam_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);
}
ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
(ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
tevent_req_nterror(req, status);
return tevent_req_post(req, ev);
}
dcerpc_binding_handle_auth_info(state->binding_handle,
&state->auth_type,
&state->auth_level);
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_SendToSam_locked,
req);
return req;
}
static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
NTSTATUS status)
{
struct netlogon_creds_cli_SendToSam_state *state =
tevent_req_data(req,
struct netlogon_creds_cli_SendToSam_state);
if (state->creds == NULL) {
return;
}
if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
!NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
!NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
TALLOC_FREE(state->creds);
return;
}
netlogon_creds_cli_delete(state->context, &state->creds);
}
static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
{
struct tevent_req *req =
tevent_req_callback_data(subreq,
struct tevent_req);
struct netlogon_creds_cli_SendToSam_state *state =
tevent_req_data(req,
struct netlogon_creds_cli_SendToSam_state);
NTSTATUS status;
status = netlogon_creds_cli_lock_recv(subreq, state,
&state->creds);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
switch (state->auth_level) {
case DCERPC_AUTH_LEVEL_INTEGRITY:
case DCERPC_AUTH_LEVEL_PRIVACY:
break;
default:
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
return;
}
} else {
uint32_t tmp = state->creds->negotiate_flags;
if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
/*
* if DCERPC_AUTH_TYPE_SCHANNEL is supported
* it should be used, which means
* we had a chance to verify no downgrade
* happened.
*
* This relies on netlogon_creds_cli_check*
* being called before, as first request after
* the DCERPC bind.
*/
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
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);
if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
netlogon_creds_aes_encrypt(&state->tmp_creds,
state->opaque.data,
state->opaque.length);
} else {
netlogon_creds_arcfour_crypt(&state->tmp_creds,
state->opaque.data,
state->opaque.length);
}
subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
state->binding_handle,
state->srv_name_slash,
state->tmp_creds.computer_name,
&state->req_auth,
&state->rep_auth,
state->opaque.data,
state->opaque.length);
if (tevent_req_nomem(subreq, req)) {
status = NT_STATUS_NO_MEMORY;
netlogon_creds_cli_SendToSam_cleanup(req, status);
return;
}
tevent_req_set_callback(subreq,
netlogon_creds_cli_SendToSam_done,
req);
}
static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
{
struct tevent_req *req =
tevent_req_callback_data(subreq,
struct tevent_req);
struct netlogon_creds_cli_SendToSam_state *state =
tevent_req_data(req,
struct netlogon_creds_cli_SendToSam_state);
NTSTATUS status;
NTSTATUS result;
bool ok;
status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
netlogon_creds_cli_SendToSam_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_SendToSam_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_SendToSam_cleanup(req, status);
return;
}
/*
* Creds must be stored before we send back application errors
* e.g. NT_STATUS_NOT_IMPLEMENTED
*/
if (tevent_req_nterror(req, result)) {
netlogon_creds_cli_SendToSam_cleanup(req, result);
return;
}
tevent_req_done(req);
}
NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
struct dcerpc_binding_handle *b,
struct netr_SendToSamBase *message)
{
TALLOC_CTX *frame = talloc_stackframe();
struct tevent_context *ev;
struct tevent_req *req;
NTSTATUS status = NT_STATUS_OK;
ev = samba_tevent_context_init(frame);
if (ev == NULL) {
goto fail;
}
req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
if (req == NULL) {
goto fail;
}
if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
/* Ignore the result */
fail:
TALLOC_FREE(frame);
return status;
}

View File

@ -181,4 +181,15 @@ NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
TALLOC_CTX *mem_ctx,
struct lsa_ForestTrustInformation **forest_trust_info);
struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct netlogon_creds_cli_context *context,
struct dcerpc_binding_handle *b,
struct netr_SendToSamBase *message);
NTSTATUS netlogon_creds_cli_SendToSam(
struct netlogon_creds_cli_context *context,
struct dcerpc_binding_handle *b,
struct netr_SendToSamBase *message);
#endif /* NETLOGON_CREDS_CLI_H */

View File

@ -1466,9 +1466,46 @@ interface netlogon
[out,ref] samr_Password *password
);
typedef [public] enum {
SendToSamUpdatePassword = 0,
SendToSamResetBadPasswordCount = 1,
SendToSamUpdatePasswordForward = 2,
SendToSamUpdateLastLogonTimestamp = 3,
SendToSamResetSmartCardPassword = 4
} netr_SendToSamType;
typedef struct {
GUID guid;
} netr_SendToSamResetBadPasswordCount;
typedef [nodiscriminant, public,switch_type(netr_SendToSamType)] union {
/* TODO Implement other SendToSam message types
* [case(SendToSamUpdatePassword)] netr_SendToSamUpdatePassword ...; */
[case(SendToSamResetBadPasswordCount)] netr_SendToSamResetBadPasswordCount reset_bad_password;
/*
* [case(SendToSamUpdatePasswordForward)] netrSendToSamUpdatePasswordForward ...;
* [case(SendToSamUpdateLastLogonTimestamp)] netrSendToSamUpdateLastLogonTimestamp ...;
* [case(SendToSamResetSmartCardPassword)] netrSendToSamResetSmartCardPassword ...;
*/
[default];
} netr_SendToSamMessage;
typedef [public] struct {
netr_SendToSamType message_type;
uint32 message_size;
[switch_is(message_type), subcontext(0), subcontext_size(message_size)] netr_SendToSamMessage message;
} netr_SendToSamBase;
/****************/
/* Function 0x20 */
[todo] WERROR netr_NETRLOGONSENDTOSAM();
NTSTATUS netr_NetrLogonSendToSam(
[in,unique] [string,charset(UTF16)] uint16 *server_name,
[in] [string,charset(UTF16)] uint16 *computer_name,
[in,ref] netr_Authenticator *credential,
[out,ref] netr_Authenticator *return_authenticator,
[in,ref] [size_is(buffer_len)] uint8 *opaque_buffer,
[in] uint32 buffer_len
);
/****************/
/* Function 0x21 */

View File

@ -211,4 +211,9 @@ interface winbind
[in] uint32 flags,
[out,ref] lsa_ForestTrustInformation **forest_trust_info
);
NTSTATUS winbind_SendToSam(
[in] netr_SendToSamBase message
);
}

View File

@ -2277,11 +2277,11 @@ NTSTATUS _netr_ServerPasswordGet(struct pipes_struct *p,
/****************************************************************
****************************************************************/
WERROR _netr_NETRLOGONSENDTOSAM(struct pipes_struct *p,
struct netr_NETRLOGONSENDTOSAM *r)
NTSTATUS _netr_NetrLogonSendToSam(struct pipes_struct *p,
struct netr_NetrLogonSendToSam *r)
{
p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
return WERR_NOT_SUPPORTED;
return NT_STATUS_NOT_IMPLEMENTED;
}
/****************************************************************

View File

@ -1701,3 +1701,28 @@ done:
TALLOC_FREE(frame);
return WERR_OK;
}
NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
{
struct winbindd_domain *domain;
NTSTATUS status;
struct rpc_pipe_client *netlogon_pipe;
DEBUG(5, ("_winbind_SendToSam received\n"));
domain = wb_child_domain();
if (domain == NULL) {
return NT_STATUS_REQUEST_NOT_ACCEPTED;
}
status = cm_connect_netlogon(domain, &netlogon_pipe);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
return status;
}
status = netlogon_creds_cli_SendToSam(domain->conn.netlogon_creds,
netlogon_pipe->binding_handle,
&r->in.message);
return status;
}

View File

@ -255,6 +255,24 @@ static NTSTATUS wb_irpc_GetForestTrustInformation(struct irpc_message *msg,
domain, 45 /* timeout */);
}
static NTSTATUS wb_irpc_SendToSam(struct irpc_message *msg,
struct winbind_SendToSam *req)
{
/* TODO make sure that it is RWDC */
struct winbindd_domain *domain = find_our_domain();
if (domain == NULL) {
return NT_STATUS_NO_SUCH_DOMAIN;
}
DEBUG(5, ("wb_irpc_SendToSam called\n"));
return wb_irpc_forward_rpc_call(msg, msg,
winbind_event_context(),
req, NDR_WINBIND_SENDTOSAM,
"winbind_SendToSam",
domain, IRPC_CALL_TIMEOUT);
}
NTSTATUS wb_irpc_register(void)
{
NTSTATUS status;
@ -281,6 +299,11 @@ NTSTATUS wb_irpc_register(void)
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_SENDTOSAM,
wb_irpc_SendToSam, NULL);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return NT_STATUS_OK;
}

View File

@ -32,6 +32,7 @@
#include "dsdb/common/util.h"
#include "param/param.h"
#include "librpc/gen_ndr/ndr_irpc_c.h"
#include "librpc/gen_ndr/ndr_winbind_c.h"
#include "lib/messaging/irpc.h"
#include "libcli/auth/libcli_auth.h"
#include "libds/common/roles.h"
@ -103,6 +104,49 @@ static NTSTATUS authsam_password_ok(struct auth4_context *auth_context,
return NT_STATUS_OK;
}
static void auth_sam_trigger_zero_password(TALLOC_CTX *mem_ctx,
struct imessaging_context *msg_ctx,
struct tevent_context *event_ctx,
struct netr_SendToSamBase *send_to_sam)
{
struct dcerpc_binding_handle *irpc_handle;
struct winbind_SendToSam r;
struct tevent_req *req;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(mem_ctx);
if (tmp_ctx == NULL) {
return;
}
irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg_ctx,
"winbind_server",
&ndr_table_winbind);
if (irpc_handle == NULL) {
DEBUG(1,(__location__ ": Unable to get binding handle for winbind\n"));
TALLOC_FREE(tmp_ctx);
return;
}
r.in.message = *send_to_sam;
/*
* This seem to rely on the current IRPC implementation,
* which delivers the message in the _send function.
*
* TODO: we need a ONE_WAY IRPC handle and register
* a callback and wait for it to be triggered!
*/
req = dcerpc_winbind_SendToSam_r_send(tmp_ctx,
event_ctx,
irpc_handle,
&r);
/* we aren't interested in a reply */
talloc_free(req);
TALLOC_FREE(tmp_ctx);
}
/*
send a message to the drepl server telling it to initiate a
@ -482,6 +526,7 @@ static NTSTATUS authsam_authenticate(struct auth4_context *auth_context,
NTSTATUS nt_status;
bool interactive = (user_info->password_state == AUTH_PASSWORD_HASH);
uint32_t acct_flags = samdb_result_acct_flags(msg, NULL);
struct netr_SendToSamBase *send_to_sam = NULL;
TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
if (!tmp_ctx) {
return NT_STATUS_NO_MEMORY;
@ -533,7 +578,16 @@ static NTSTATUS authsam_authenticate(struct auth4_context *auth_context,
nt_status = authsam_logon_success_accounting(auth_context->sam_ctx,
msg, domain_dn,
interactive);
interactive,
&send_to_sam);
if (send_to_sam != NULL) {
auth_sam_trigger_zero_password(tmp_ctx,
auth_context->msg_ctx,
auth_context->event_ctx,
send_to_sam);
}
if (!NT_STATUS_IS_OK(nt_status)) {
TALLOC_FREE(tmp_ctx);
return nt_status;

View File

@ -225,7 +225,8 @@ static NTSTATUS winbind_check_password(struct auth_method_context *ctx,
if (NT_STATUS_IS_OK(status)) {
authsam_logon_success_accounting(ctx->auth_ctx->sam_ctx, msg,
domain_dn,
user_info->flags & USER_INFO_INTERACTIVE_LOGON);
user_info->flags & USER_INFO_INTERACTIVE_LOGON,
NULL);
}
}
}

View File

@ -30,6 +30,7 @@
#include "dsdb/common/util.h"
#include "libcli/ldap/ldap_ndr.h"
#include "param/param.h"
#include "librpc/gen_ndr/ndr_winbind_c.h"
#define KRBTGT_ATTRS \
/* required for the krb5 kdc */ \
@ -74,9 +75,14 @@ const char *user_attrs[] = {
*/
"lockoutTime",
/*
* Needed for SendToSAM requests
*/
"objectGUID",
/* check 'allowed workstations' */
"userWorkstations",
/* required for user_info_dc, not access control: */
"displayName",
"scriptPath",
@ -871,11 +877,13 @@ NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx
NTSTATUS authsam_logon_success_accounting(struct ldb_context *sam_ctx,
const struct ldb_message *msg,
struct ldb_dn *domain_dn,
bool interactive_or_kerberos)
bool interactive_or_kerberos,
struct netr_SendToSamBase **send_to_sam)
{
int ret;
NTSTATUS status;
int badPwdCount;
int dbBadPwdCount;
int64_t lockoutTime;
struct ldb_message *msg_mod;
TALLOC_CTX *mem_ctx;
@ -890,8 +898,9 @@ NTSTATUS authsam_logon_success_accounting(struct ldb_context *sam_ctx,
}
lockoutTime = ldb_msg_find_attr_as_int64(msg, "lockoutTime", 0);
dbBadPwdCount = ldb_msg_find_attr_as_int(msg, "badPwdCount", 0);
if (interactive_or_kerberos) {
badPwdCount = ldb_msg_find_attr_as_int(msg, "badPwdCount", 0);
badPwdCount = dbBadPwdCount;
} else {
badPwdCount = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx,
domain_dn, msg);
@ -971,13 +980,24 @@ NTSTATUS authsam_logon_success_accounting(struct ldb_context *sam_ctx,
}
if (!am_rodc) {
/* TODO Perform the (async) SendToSAM calls for MS-SAMS */
status = authsam_update_lastlogon_timestamp(sam_ctx, msg_mod, domain_dn,
lastLogonTimestamp, now);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
} else {
/* Perform the (async) SendToSAM calls for MS-SAMS */
if (dbBadPwdCount != 0 && send_to_sam != NULL) {
struct netr_SendToSamBase *base_msg;
struct GUID guid = samdb_result_guid(msg, "objectGUID");
base_msg = talloc_zero(msg, struct netr_SendToSamBase);
base_msg->message_type = SendToSamResetBadPasswordCount;
base_msg->message_size = 16;
base_msg->message.reset_bad_password.guid = guid;
*send_to_sam = base_msg;
}
}
if (msg_mod->num_elements > 0) {

View File

@ -296,6 +296,28 @@ hdb_samba4_check_s4u2self(krb5_context context, HDB *db,
return ret;
}
static void reset_bad_password_netlogon(TALLOC_CTX *mem_ctx,
struct samba_kdc_db_context *kdc_db_ctx,
struct netr_SendToSamBase *send_to_sam)
{
struct dcerpc_binding_handle *irpc_handle;
struct winbind_SendToSam req;
irpc_handle = irpc_binding_handle_by_name(mem_ctx, kdc_db_ctx->msg_ctx,
"winbind_server",
&ndr_table_winbind);
if (irpc_handle == NULL) {
DEBUG(0, ("No winbind_server running!\n"));
return;
}
req.in.message = *send_to_sam;
dcerpc_winbind_SendToSam_r_send(mem_ctx, kdc_db_ctx->ev_ctx,
irpc_handle, &req);
}
static void send_bad_password_netlogon(TALLOC_CTX *mem_ctx,
struct samba_kdc_db_context *kdc_db_ctx,
struct auth_usersupplied_info *user_info)
@ -396,8 +418,10 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, HDB *db,
switch (hdb_auth_status) {
case HDB_AUTHZ_SUCCESS:
{
TALLOC_CTX *frame = talloc_stackframe();
struct samba_kdc_entry *p = talloc_get_type(entry->ctx,
struct samba_kdc_entry);
struct netr_SendToSamBase *send_to_sam = NULL;
/*
* TODO: We could log the AS-REQ authorization success here as
@ -405,7 +429,11 @@ static krb5_error_code hdb_samba4_auth_status(krb5_context context, HDB *db,
* in the PAC here or re-calculate it.
*/
authsam_logon_success_accounting(kdc_db_ctx->samdb, p->msg,
domain_dn, true);
domain_dn, true, &send_to_sam);
if (kdc_db_ctx->rodc && send_to_sam != NULL) {
reset_bad_password_netlogon(frame, kdc_db_ctx, send_to_sam);
}
talloc_free(frame);
break;
}
case HDB_AUTH_INVALID_SIGNATURE:

View File

@ -2254,12 +2254,104 @@ static NTSTATUS dcesrv_netr_ServerPasswordGet(struct dcesrv_call_state *dce_call
/*
netr_NETRLOGONSENDTOSAM
netr_NetrLogonSendToSam
*/
static WERROR dcesrv_netr_NETRLOGONSENDTOSAM(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_NETRLOGONSENDTOSAM *r)
static NTSTATUS dcesrv_netr_NetrLogonSendToSam(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct netr_NetrLogonSendToSam *r)
{
DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
struct netlogon_creds_CredentialState *creds;
struct ldb_context *sam_ctx;
NTSTATUS nt_status;
DATA_BLOB decrypted_blob;
enum ndr_err_code ndr_err;
struct netr_SendToSamBase base_msg = { 0 };
nt_status = dcesrv_netr_creds_server_step_check(dce_call,
mem_ctx,
r->in.computer_name,
r->in.credential,
r->out.return_authenticator,
&creds);
NT_STATUS_NOT_OK_RETURN(nt_status);
switch (creds->secure_channel_type) {
case SEC_CHAN_BDC:
case SEC_CHAN_RODC:
break;
case SEC_CHAN_WKSTA:
case SEC_CHAN_DNS_DOMAIN:
case SEC_CHAN_DOMAIN:
case SEC_CHAN_NULL:
return NT_STATUS_INVALID_PARAMETER;
default:
DEBUG(1, ("Client asked for an invalid secure channel type: %d\n",
creds->secure_channel_type));
return NT_STATUS_INVALID_PARAMETER;
}
sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
dce_call->conn->dce_ctx->lp_ctx,
system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
if (sam_ctx == NULL) {
return NT_STATUS_INVALID_SYSTEM_SERVICE;
}
/* Buffer is meant to be 16-bit aligned */
if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
netlogon_creds_aes_decrypt(creds, r->in.opaque_buffer, r->in.buffer_len);
} else {
netlogon_creds_arcfour_crypt(creds, r->in.opaque_buffer, r->in.buffer_len);
}
decrypted_blob.data = r->in.opaque_buffer;
decrypted_blob.length = r->in.buffer_len;
ndr_err = ndr_pull_struct_blob(&decrypted_blob, mem_ctx, &base_msg,
(ndr_pull_flags_fn_t)ndr_pull_netr_SendToSamBase);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
/* We only partially implement SendToSam */
return NT_STATUS_NOT_IMPLEMENTED;
}
/* Now 'send' to SAM */
switch (base_msg.message_type) {
case SendToSamResetBadPasswordCount:
{
struct ldb_message *msg = ldb_msg_new(mem_ctx);
struct ldb_dn *dn = NULL;
int ret = 0;
ret = dsdb_find_dn_by_guid(sam_ctx,
mem_ctx,
&base_msg.message.reset_bad_password.guid,
0,
&dn);
if (ret != LDB_SUCCESS) {
return NT_STATUS_INVALID_PARAMETER;
}
msg->dn = dn;
ret = samdb_msg_add_int(sam_ctx, mem_ctx, msg, "badPwdCount", 0);
if (ret != LDB_SUCCESS) {
return NT_STATUS_INVALID_PARAMETER;
}
ret = dsdb_replace(sam_ctx, msg, 0);
if (ret != LDB_SUCCESS) {
return NT_STATUS_INVALID_PARAMETER;
}
break;
}
default:
return NT_STATUS_NOT_IMPLEMENTED;
}
return NT_STATUS_OK;
}