diff options
author | Stefan Metzmacher <metze@samba.org> | 2015-07-20 14:00:05 +0200 |
---|---|---|
committer | Günther Deschner <gd@samba.org> | 2019-09-20 01:14:43 +0000 |
commit | 6e47f9ab37744d628cc6b723f4838e81202f2df6 (patch) | |
tree | 3612996ddd524b9b0f3afdf32ff9f13c515f95f1 /libcli | |
parent | 8f0751b8b7cd45fc7186b467d814eb5231821e34 (diff) | |
download | samba-6e47f9ab37744d628cc6b723f4838e81202f2df6.tar.gz |
libcli/auth: add netlogon_creds_cli_LogonGetDomainInfo()
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Guenther Deschner <gd@samba.org>
Diffstat (limited to 'libcli')
-rw-r--r-- | libcli/auth/netlogon_creds_cli.c | 281 | ||||
-rw-r--r-- | libcli/auth/netlogon_creds_cli.h | 17 |
2 files changed, 297 insertions, 1 deletions
diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c index c5a100c3c0e..3cc18e7fa60 100644 --- a/libcli/auth/netlogon_creds_cli.c +++ b/libcli/auth/netlogon_creds_cli.c @@ -3528,7 +3528,6 @@ 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; @@ -3793,3 +3792,283 @@ NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context TALLOC_FREE(frame); return status; } + +struct netlogon_creds_cli_LogonGetDomainInfo_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; + + uint32_t level; + union netr_WorkstationInfo *query; + union netr_DomainInfo *info; + + 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_LogonGetDomainInfo_cleanup(struct tevent_req *req, + NTSTATUS status); +static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq); + +struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct netlogon_creds_cli_context *context, + struct dcerpc_binding_handle *b, + uint32_t level, + union netr_WorkstationInfo *query) +{ + struct tevent_req *req; + struct netlogon_creds_cli_LogonGetDomainInfo_state *state; + struct tevent_req *subreq; + + req = tevent_req_create(mem_ctx, &state, + struct netlogon_creds_cli_LogonGetDomainInfo_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->level = level; + state->query = query; + state->info = talloc_zero(state, union netr_DomainInfo); + if (tevent_req_nomem(state->info, req)) { + 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_LogonGetDomainInfo_locked, + req); + + return req; +} + +static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req, + NTSTATUS status) +{ + struct netlogon_creds_cli_LogonGetDomainInfo_state *state = + tevent_req_data(req, + struct netlogon_creds_cli_LogonGetDomainInfo_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_LogonGetDomainInfo_done(struct tevent_req *subreq); + +static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct netlogon_creds_cli_LogonGetDomainInfo_state *state = + tevent_req_data(req, + struct netlogon_creds_cli_LogonGetDomainInfo_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); + + subreq = dcerpc_netr_LogonGetDomainInfo_send(state, state->ev, + state->binding_handle, + state->srv_name_slash, + state->tmp_creds.computer_name, + &state->req_auth, + &state->rep_auth, + state->level, + state->query, + state->info); + if (tevent_req_nomem(subreq, req)) { + status = NT_STATUS_NO_MEMORY; + netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status); + return; + } + + tevent_req_set_callback(subreq, + netlogon_creds_cli_LogonGetDomainInfo_done, + req); +} + +static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct netlogon_creds_cli_LogonGetDomainInfo_state *state = + tevent_req_data(req, + struct netlogon_creds_cli_LogonGetDomainInfo_state); + NTSTATUS status; + NTSTATUS result; + bool ok; + + /* + * We use state->dns_names as the memory context, as this is + * the only in/out variable and it has been overwritten by the + * out parameter from the server. + * + * We need to preserve the return value until the caller can use it. + */ + status = dcerpc_netr_LogonGetDomainInfo_recv(subreq, state->info, &result); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + netlogon_creds_cli_LogonGetDomainInfo_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_LogonGetDomainInfo_cleanup(req, status); + return; + } + + if (tevent_req_nterror(req, result)) { + netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result); + return; + } + + *state->creds = state->tmp_creds; + status = netlogon_creds_cli_store(state->context, + state->creds); + if (tevent_req_nterror(req, status)) { + netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status); + return; + } + + tevent_req_done(req); +} + +NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + union netr_DomainInfo **info) +{ + struct netlogon_creds_cli_LogonGetDomainInfo_state *state = + tevent_req_data(req, + struct netlogon_creds_cli_LogonGetDomainInfo_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status); + tevent_req_received(req); + return status; + } + + *info = talloc_move(mem_ctx, &state->info); + + tevent_req_received(req); + return NT_STATUS_OK; +} + +NTSTATUS netlogon_creds_cli_LogonGetDomainInfo( + struct netlogon_creds_cli_context *context, + struct dcerpc_binding_handle *b, + TALLOC_CTX *mem_ctx, + uint32_t level, + union netr_WorkstationInfo *query, + union netr_DomainInfo **info) +{ + 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_LogonGetDomainInfo_send(frame, ev, context, b, + level, query); + if (req == NULL) { + goto fail; + } + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + status = netlogon_creds_cli_LogonGetDomainInfo_recv(req, + mem_ctx, + info); + fail: + TALLOC_FREE(frame); + return status; +} diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h index 56a2dd9bc77..7fb41872c36 100644 --- a/libcli/auth/netlogon_creds_cli.h +++ b/libcli/auth/netlogon_creds_cli.h @@ -214,4 +214,21 @@ NTSTATUS netlogon_creds_cli_SendToSam( struct dcerpc_binding_handle *b, struct netr_SendToSamBase *message); +struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct netlogon_creds_cli_context *context, + struct dcerpc_binding_handle *b, + uint32_t level, + union netr_WorkstationInfo *query); +NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + union netr_DomainInfo **info); +NTSTATUS netlogon_creds_cli_LogonGetDomainInfo( + struct netlogon_creds_cli_context *context, + struct dcerpc_binding_handle *b, + TALLOC_CTX *mem_ctx, + uint32_t level, + union netr_WorkstationInfo *query, + union netr_DomainInfo **info); + #endif /* NETLOGON_CREDS_CLI_H */ |