dcesrv_netr_generic_delay ...
authorStefan Metzmacher <metze@samba.org>
Wed, 13 Nov 2013 07:34:25 +0000 (08:34 +0100)
committerStefan Metzmacher <metze@samba.org>
Wed, 11 Apr 2018 07:10:29 +0000 (09:10 +0200)
source4/rpc_server/netlogon/dcerpc_netlogon.c

index 60761b8b3ee0e4ed540bb96f85db73f4694e4cb5..b570dac08f9ac167a64e951cae15d74c7c50d4de 100644 (file)
@@ -63,6 +63,64 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_call_state *dce_cal
        return dcesrv_interface_bind_reject_connect(dce_call, iface);
 }
 
+static void dcesrv_netr_generic_delay_done(struct tevent_req *subreq);
+
+static NTSTATUS dcesrv_netr_generic_delay(struct dcesrv_call_state *dce_call,
+                                         const char *name)
+{
+       long to_min = lpcfg_parm_long(dce_call->conn->dce_ctx->lp_ctx, NULL,
+                                     "netlogon delay min", name, 0);
+       long to_max = lpcfg_parm_long(dce_call->conn->dce_ctx->lp_ctx, NULL,
+                                     "netlogon delay max", name, 0);
+       long to_range = 0;
+       long to_random = 0;
+       long delay = 0;
+       struct timeval to;
+       struct tevent_req *subreq;
+
+       if (to_max > to_min) {
+               to_range = (to_max - to_min) + 1;
+               to_random = generate_random() % to_range;
+       }
+
+       delay = to_min + to_random;
+
+       if (delay == 0) {
+               return NT_STATUS_OK;
+       }
+
+       to = timeval_current_ofs(delay, 0);
+
+       /* forward the call */
+       subreq = tevent_wakeup_send(dce_call, dce_call->event_ctx, to);
+       NT_STATUS_HAVE_NO_MEMORY(subreq);
+
+       dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC;
+
+       /* setup the callback */
+       tevent_req_set_callback(subreq,
+                               dcesrv_netr_generic_delay_done,
+                               dce_call);
+
+       return NT_STATUS_OK;
+}
+
+static void dcesrv_netr_generic_delay_done(struct tevent_req *subreq)
+{
+       struct dcesrv_call_state *dce_call =
+               tevent_req_callback_data(subreq,
+               struct dcesrv_call_state);
+       NTSTATUS status;
+
+       tevent_wakeup_recv(subreq);
+       TALLOC_FREE(subreq);
+
+       status = dcesrv_reply(dce_call);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,(__location__ ": dcesrv_reply() failed - %s\n", nt_errstr(status)));
+       }
+}
+
 struct netlogon_server_pipe_state {
        struct netr_Credential client_challenge;
        struct netr_Credential server_challenge;
@@ -730,6 +788,11 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet(struct dcesrv_call_state *dce_call
                                           NULL, r->in.new_password,
                                           NULL, oldNtHash, /* Password change */
                                           NULL, NULL);
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
+       nt_status = dcesrv_netr_generic_delay(dce_call, "password set");
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
        return nt_status;
 }
 
@@ -825,6 +888,11 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal
                                           NULL, NULL,
                                           oldLmHash, oldNtHash, /* Password change */
                                           NULL, NULL);
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
+       nt_status = dcesrv_netr_generic_delay(dce_call, "password set2");
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
        return nt_status;
 }
 
@@ -1268,6 +1336,7 @@ static void dcesrv_netr_LogonSamLogon_base_reply(
 {
        struct netr_LogonSamLogonEx *r = &state->r;
        NTSTATUS status;
+       const char *name = NULL;
 
        if (NT_STATUS_IS_OK(r->out.result)) {
                netlogon_creds_encrypt_samlogon_validation(state->creds,
@@ -1278,12 +1347,23 @@ static void dcesrv_netr_LogonSamLogon_base_reply(
        if (state->_r.lslex != NULL) {
                struct netr_LogonSamLogonEx *_r = state->_r.lslex;
                _r->out.result = r->out.result;
+               name = "logon ex";
        } else if (state->_r.lslwf != NULL) {
                struct netr_LogonSamLogonWithFlags *_r = state->_r.lslwf;
                _r->out.result = r->out.result;
+               name = "logon with flags";
        } else if (state->_r.lsl != NULL) {
                struct netr_LogonSamLogon *_r = state->_r.lsl;
                _r->out.result = r->out.result;
+               name = "logon";
+       }
+
+       status = dcesrv_netr_generic_delay(dce_call, logon);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("dcesrv_netr_generic_delay(%s) failed - %s\n",
+                       name, nt_errstr(status));
+       } else {
+               return;
        }
 
        status = dcesrv_reply(state->dce_call);
@@ -1343,6 +1423,11 @@ static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call,
                return nt_status;
        }
 
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
+       nt_status = dcesrv_netr_generic_delay(dce_call, "logon ex");
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
        return nt_status;
 }
 
@@ -1405,6 +1490,11 @@ static NTSTATUS dcesrv_netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce
                return nt_status;
        }
 
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
+       nt_status = dcesrv_netr_generic_delay(dce_call, "logon with flags");
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
        return nt_status;
 }
 
@@ -1466,6 +1556,11 @@ static NTSTATUS dcesrv_netr_LogonSamLogon(struct dcesrv_call_state *dce_call, TA
                return nt_status;
        }
 
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
+       nt_status = dcesrv_netr_generic_delay(dce_call, "logon");
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
        return nt_status;
 }
 
@@ -2088,6 +2183,9 @@ static NTSTATUS dcesrv_netr_LogonGetCapabilities(struct dcesrv_call_state *dce_c
 
        r->out.capabilities->server_capabilities = creds->negotiate_flags;
 
+       status = dcesrv_netr_generic_delay(dce_call, "capabilities");
+       NT_STATUS_NOT_OK_RETURN(status);
+
        return NT_STATUS_OK;
 }