* RPC Pipe client routines
* Largely rewritten by Jeremy Allison 2005.
* Heavily modified by Simo Sorce 2010.
+ * Copyright Andrew Bartlett 2011.
*
* 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
*/
#include "includes.h"
-#include "librpc/gen_ndr/cli_epmapper.h"
-#include "../librpc/gen_ndr/ndr_schannel.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "librpc/gen_ndr/ndr_epmapper_c.h"
#include "../librpc/gen_ndr/ndr_dssetup.h"
#include "../libcli/auth/schannel.h"
-#include "../libcli/auth/spnego.h"
-#include "smb_krb5.h"
-#include "../libcli/auth/ntlmssp.h"
-#include "ntlmssp_wrap.h"
+#include "auth_generic.h"
#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
#include "librpc/rpc/dcerpc.h"
-#include "librpc/crypto/gse.h"
-#include "librpc/crypto/spnego.h"
#include "rpc_dce.h"
+#include "cli_pipe.h"
+#include "libsmb/libsmb.h"
+#include "auth/gensec/gensec.h"
+#include "auth/credentials/credentials.h"
+#include "../libcli/smb/smbXcli_base.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_CLI
********************************************************************/
struct rpc_read_state {
- struct event_context *ev;
+ struct tevent_context *ev;
struct rpc_cli_transport *transport;
uint8_t *data;
size_t size;
static void rpc_read_done(struct tevent_req *subreq);
static struct tevent_req *rpc_read_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
+ struct tevent_context *ev,
struct rpc_cli_transport *transport,
uint8_t *data, size_t size)
{
}
struct rpc_write_state {
- struct event_context *ev;
+ struct tevent_context *ev;
struct rpc_cli_transport *transport;
const uint8_t *data;
size_t size;
static void rpc_write_done(struct tevent_req *subreq);
static struct tevent_req *rpc_write_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
+ struct tevent_context *ev,
struct rpc_cli_transport *transport,
const uint8_t *data, size_t size)
{
****************************************************************************/
struct get_complete_frag_state {
- struct event_context *ev;
+ struct tevent_context *ev;
struct rpc_pipe_client *cli;
uint16_t frag_len;
DATA_BLOB *pdu;
static void get_complete_frag_got_rest(struct tevent_req *subreq);
static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
+ struct tevent_context *ev,
struct rpc_pipe_client *cli,
DATA_BLOB *pdu)
{
pkt->u.fault.status),
rpccli_pipe_txt(talloc_tos(), cli)));
- if (NT_STATUS_IS_OK(NT_STATUS(pkt->u.fault.status))) {
- return NT_STATUS_UNSUCCESSFUL;
- } else {
- return NT_STATUS(pkt->u.fault.status);
- }
+ return dcerpc_fault_to_nt_status(pkt->u.fault.status);
default:
DEBUG(0, (__location__ "Unknown packet type %u received "
****************************************************************************/
struct cli_api_pipe_state {
- struct event_context *ev;
+ struct tevent_context *ev;
struct rpc_cli_transport *transport;
uint8_t *rdata;
uint32_t rdata_len;
static void cli_api_pipe_read_done(struct tevent_req *subreq);
static struct tevent_req *cli_api_pipe_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
+ struct tevent_context *ev,
struct rpc_cli_transport *transport,
uint8_t *data, size_t data_len,
uint32_t max_rdata_len)
return;
}
- state->rdata = TALLOC_ARRAY(state, uint8_t, RPC_HEADER_LEN);
+ state->rdata = talloc_array(state, uint8_t, RPC_HEADER_LEN);
if (tevent_req_nomem(state->rdata, req)) {
return;
}
****************************************************************************/
struct rpc_api_pipe_state {
- struct event_context *ev;
+ struct tevent_context *ev;
struct rpc_pipe_client *cli;
uint8_t expected_pkt_type;
static void rpc_api_pipe_auth3_done(struct tevent_req *subreq);
static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
+ struct tevent_context *ev,
struct rpc_pipe_client *cli,
DATA_BLOB *data, /* Outgoing PDU */
uint8_t expected_pkt_type)
state->ev = ev;
state->cli = cli;
state->expected_pkt_type = expected_pkt_type;
- state->incoming_frag = data_blob_null;
- state->reply_pdu = data_blob_null;
- state->reply_pdu_offset = 0;
state->endianess = DCERPC_DREP_LE;
/*
return NT_STATUS_OK;
}
-/*******************************************************************
- Creates spnego auth bind.
- ********************************************************************/
-
-static NTSTATUS create_spnego_auth_bind_req(TALLOC_CTX *mem_ctx,
- struct pipe_auth_data *auth,
- DATA_BLOB *auth_token)
-{
- DATA_BLOB in_token = data_blob_null;
- NTSTATUS status;
-
- /* Negotiate the initial auth token */
- status = spnego_get_client_auth_token(mem_ctx,
- auth->a_u.spnego_state,
- &in_token, auth_token);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- DEBUG(5, ("Created GSS Authentication Token:\n"));
- dump_data(5, auth_token->data, auth_token->length);
-
- return NT_STATUS_OK;
-}
-
-/*******************************************************************
- Creates krb5 auth bind.
- ********************************************************************/
-
-static NTSTATUS create_gssapi_auth_bind_req(TALLOC_CTX *mem_ctx,
- struct pipe_auth_data *auth,
- DATA_BLOB *auth_token)
-{
- DATA_BLOB in_token = data_blob_null;
- NTSTATUS status;
-
- /* Negotiate the initial auth token */
- status = gse_get_client_auth_token(mem_ctx,
- auth->a_u.gssapi_state,
- &in_token,
- auth_token);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- DEBUG(5, ("Created GSS Authentication Token:\n"));
- dump_data(5, auth_token->data, auth_token->length);
-
- return NT_STATUS_OK;
-}
-
/*******************************************************************
Creates NTLMSSP auth bind.
********************************************************************/
-static NTSTATUS create_ntlmssp_auth_rpc_bind_req(struct rpc_pipe_client *cli,
+static NTSTATUS create_generic_auth_rpc_bind_req(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
DATA_BLOB *auth_token)
{
- NTSTATUS status;
+ struct gensec_security *gensec_security;
DATA_BLOB null_blob = data_blob_null;
- DEBUG(5, ("create_ntlmssp_auth_rpc_bind_req: Processing NTLMSSP Negotiate\n"));
- status = auth_ntlmssp_update(cli->auth->a_u.auth_ntlmssp_state,
- null_blob, auth_token);
-
- if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- data_blob_free(auth_token);
- return status;
- }
-
- DEBUG(5, ("create_ntlmssp_auth_rpc_bind_req: NTLMSSP Negotiate:\n"));
- dump_data(5, auth_token->data, auth_token->length);
-
- return NT_STATUS_OK;
-}
-
-/*******************************************************************
- Creates schannel auth bind.
- ********************************************************************/
-
-static NTSTATUS create_schannel_auth_rpc_bind_req(struct rpc_pipe_client *cli,
- DATA_BLOB *auth_token)
-{
- NTSTATUS status;
- struct NL_AUTH_MESSAGE r;
-
- /* Use lp_workgroup() if domain not specified */
-
- if (!cli->auth->domain || !cli->auth->domain[0]) {
- cli->auth->domain = talloc_strdup(cli, lp_workgroup());
- if (cli->auth->domain == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- }
-
- /*
- * Now marshall the data into the auth parse_struct.
- */
-
- r.MessageType = NL_NEGOTIATE_REQUEST;
- r.Flags = NL_FLAG_OEM_NETBIOS_DOMAIN_NAME |
- NL_FLAG_OEM_NETBIOS_COMPUTER_NAME;
- r.oem_netbios_domain.a = cli->auth->domain;
- r.oem_netbios_computer.a = global_myname();
-
- status = dcerpc_push_schannel_bind(cli, &r, auth_token);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
+ gensec_security = talloc_get_type_abort(cli->auth->auth_ctx,
+ struct gensec_security);
- return NT_STATUS_OK;
+ DEBUG(5, ("create_generic_auth_rpc_bind_req: generate first token\n"));
+ return gensec_update(gensec_security, mem_ctx, NULL, null_blob, auth_token);
}
/*******************************************************************
switch (auth->auth_type) {
case DCERPC_AUTH_TYPE_SCHANNEL:
- ret = create_schannel_auth_rpc_bind_req(cli, &auth_token);
- if (!NT_STATUS_IS_OK(ret)) {
- return ret;
- }
- break;
-
case DCERPC_AUTH_TYPE_NTLMSSP:
- ret = create_ntlmssp_auth_rpc_bind_req(cli, &auth_token);
- if (!NT_STATUS_IS_OK(ret)) {
- return ret;
- }
- break;
-
+ case DCERPC_AUTH_TYPE_KRB5:
case DCERPC_AUTH_TYPE_SPNEGO:
- ret = create_spnego_auth_bind_req(cli, auth, &auth_token);
- if (!NT_STATUS_IS_OK(ret)) {
+ ret = create_generic_auth_rpc_bind_req(cli, mem_ctx, &auth_token);
+
+ if (!NT_STATUS_IS_OK(ret) &&
+ !NT_STATUS_EQUAL(ret, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
return ret;
}
break;
- case DCERPC_AUTH_TYPE_KRB5:
- ret = create_gssapi_auth_bind_req(mem_ctx, auth, &auth_token);
- if (!NT_STATUS_IS_OK(ret)) {
- return ret;
- }
+ case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
+ auth_token = data_blob_talloc(mem_ctx,
+ "NCALRPC_AUTH_TOKEN",
+ 18);
break;
case DCERPC_AUTH_TYPE_NONE:
********************************************************************/
struct rpc_api_pipe_req_state {
- struct event_context *ev;
+ struct tevent_context *ev;
struct rpc_pipe_client *cli;
uint8_t op_num;
uint32_t call_id;
bool *is_last_frag);
struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
+ struct tevent_context *ev,
struct rpc_pipe_client *cli,
uint8_t op_num,
DATA_BLOB *req_data)
****************************************************************************/
struct rpc_pipe_bind_state {
- struct event_context *ev;
+ struct tevent_context *ev;
struct rpc_pipe_client *cli;
DATA_BLOB rpc_out;
bool auth3;
DATA_BLOB *credentials);
struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
+ struct tevent_context *ev,
struct rpc_pipe_client *cli,
struct pipe_auth_data *auth)
{
return NULL;
}
- DEBUG(5,("Bind RPC Pipe: %s auth_type %u(%u), auth_level %u\n",
+ DEBUG(5,("Bind RPC Pipe: %s auth_type %u, auth_level %u\n",
rpccli_pipe_txt(talloc_tos(), cli),
(unsigned int)auth->auth_type,
- (unsigned int)auth->spnego_type,
(unsigned int)auth->auth_level ));
state->ev = ev;
&cli->transfer_syntax,
&state->rpc_out);
- if (!NT_STATUS_IS_OK(status)) {
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
goto post_status;
}
struct rpc_pipe_bind_state *state = tevent_req_data(
req, struct rpc_pipe_bind_state);
struct pipe_auth_data *pauth = state->cli->auth;
- struct ncacn_packet *pkt;
+ struct gensec_security *gensec_security;
+ struct ncacn_packet *pkt = NULL;
struct dcerpc_auth auth;
DATA_BLOB auth_token = data_blob_null;
NTSTATUS status;
switch(pauth->auth_type) {
case DCERPC_AUTH_TYPE_NONE:
+ case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
case DCERPC_AUTH_TYPE_SCHANNEL:
/* Bind complete. */
tevent_req_done(req);
switch(pauth->auth_type) {
case DCERPC_AUTH_TYPE_NONE:
+ case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
case DCERPC_AUTH_TYPE_SCHANNEL:
/* Bind complete. */
tevent_req_done(req);
return;
case DCERPC_AUTH_TYPE_NTLMSSP:
- status = auth_ntlmssp_update(pauth->a_u.auth_ntlmssp_state,
- auth.credentials, &auth_token);
+ case DCERPC_AUTH_TYPE_KRB5:
+ case DCERPC_AUTH_TYPE_SPNEGO:
+ gensec_security = talloc_get_type_abort(pauth->auth_ctx,
+ struct gensec_security);
+ status = gensec_update(gensec_security, state, NULL,
+ auth.credentials, &auth_token);
if (NT_STATUS_EQUAL(status,
NT_STATUS_MORE_PROCESSING_REQUIRED)) {
status = rpc_bind_next_send(req, state,
&auth_token);
} else if (NT_STATUS_IS_OK(status)) {
+ if (auth_token.length == 0) {
+ /* Bind complete. */
+ tevent_req_done(req);
+ return;
+ }
status = rpc_bind_finish_send(req, state,
&auth_token);
}
break;
- case DCERPC_AUTH_TYPE_SPNEGO:
- status = spnego_get_client_auth_token(state,
- pauth->a_u.spnego_state,
- &auth.credentials,
- &auth_token);
- if (!NT_STATUS_IS_OK(status)) {
- break;
- }
- if (auth_token.length == 0) {
- /* Bind complete. */
- tevent_req_done(req);
- return;
- }
- if (spnego_require_more_processing(pauth->a_u.spnego_state)) {
- status = rpc_bind_next_send(req, state,
- &auth_token);
- } else {
- status = rpc_bind_finish_send(req, state,
- &auth_token);
- }
- break;
-
- case DCERPC_AUTH_TYPE_KRB5:
- status = gse_get_client_auth_token(state,
- pauth->a_u.gssapi_state,
- &auth.credentials,
- &auth_token);
- if (!NT_STATUS_IS_OK(status)) {
- break;
- }
-
- if (gse_require_more_processing(pauth->a_u.gssapi_state)) {
- status = rpc_bind_next_send(req, state, &auth_token);
- } else {
- status = rpc_bind_finish_send(req, state, &auth_token);
- }
- break;
-
default:
goto err_out;
}
return;
err_out:
- DEBUG(0,("cli_finish_bind_auth: unknown auth type %u(%u)\n",
- (unsigned int)state->cli->auth->auth_type,
- (unsigned int)state->cli->auth->spnego_type));
+ DEBUG(0,("cli_finish_bind_auth: unknown auth type %u\n",
+ (unsigned int)state->cli->auth->auth_type));
tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
}
struct pipe_auth_data *auth)
{
TALLOC_CTX *frame = talloc_stackframe();
- struct event_context *ev;
+ struct tevent_context *ev;
struct tevent_req *req;
NTSTATUS status = NT_STATUS_OK;
- ev = event_context_init(frame);
+ ev = samba_tevent_context_init(frame);
if (ev == NULL) {
status = NT_STATUS_NO_MEMORY;
goto fail;
return rpccli_set_timeout(hs->rpc_cli, timeout);
}
+static void rpccli_bh_auth_info(struct dcerpc_binding_handle *h,
+ enum dcerpc_AuthType *auth_type,
+ enum dcerpc_AuthLevel *auth_level)
+{
+ struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
+ struct rpccli_bh_state);
+
+ if (hs->rpc_cli == NULL) {
+ return;
+ }
+
+ if (hs->rpc_cli->auth == NULL) {
+ return;
+ }
+
+ *auth_type = hs->rpc_cli->auth->auth_type;
+ *auth_level = hs->rpc_cli->auth->auth_level;
+}
+
struct rpccli_bh_raw_call_state {
DATA_BLOB in_data;
DATA_BLOB out_data;
ok = rpccli_bh_is_connected(h);
if (!ok) {
- tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
+ tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
return tevent_req_post(req, ev);
}
ok = rpccli_bh_is_connected(h);
if (!ok) {
- tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
+ tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
return tevent_req_post(req, ev);
}
.name = "rpccli",
.is_connected = rpccli_bh_is_connected,
.set_timeout = rpccli_bh_set_timeout,
+ .auth_info = rpccli_bh_auth_info,
.raw_call_send = rpccli_bh_raw_call_send,
.raw_call_recv = rpccli_bh_raw_call_recv,
.disconnect_send = rpccli_bh_disconnect_send,
};
/* initialise a rpc_pipe_client binding handle */
-static struct dcerpc_binding_handle *rpccli_bh_create(struct rpc_pipe_client *c)
+struct dcerpc_binding_handle *rpccli_bh_create(struct rpc_pipe_client *c)
{
struct dcerpc_binding_handle *h;
struct rpccli_bh_state *hs;
return h;
}
-bool rpccli_get_pwd_hash(struct rpc_pipe_client *rpc_cli, uint8_t nt_hash[16])
+NTSTATUS rpccli_ncalrpc_bind_data(TALLOC_CTX *mem_ctx,
+ struct pipe_auth_data **presult)
{
- struct auth_ntlmssp_state *a = NULL;
- struct cli_state *cli;
-
- if (rpc_cli->auth->auth_type == DCERPC_AUTH_TYPE_NTLMSSP) {
- a = rpc_cli->auth->a_u.auth_ntlmssp_state;
- } else if (rpc_cli->auth->auth_type == DCERPC_AUTH_TYPE_SPNEGO) {
- enum spnego_mech auth_type;
- void *auth_ctx;
- NTSTATUS status;
-
- status = spnego_get_negotiated_mech(
- rpc_cli->auth->a_u.spnego_state,
- &auth_type, &auth_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- return false;
- }
+ struct pipe_auth_data *result;
- if (auth_type == SPNEGO_NTLMSSP) {
- a = talloc_get_type(auth_ctx,
- struct auth_ntlmssp_state);
- }
+ result = talloc(mem_ctx, struct pipe_auth_data);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
- if (a) {
- memcpy(nt_hash, auth_ntlmssp_get_nt_hash(a), 16);
- return true;
- }
+ result->auth_type = DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM;
+ result->auth_level = DCERPC_AUTH_LEVEL_CONNECT;
- cli = rpc_pipe_np_smb_conn(rpc_cli);
- if (cli == NULL) {
- return false;
+ result->user_name = talloc_strdup(result, "");
+ result->domain = talloc_strdup(result, "");
+ if ((result->user_name == NULL) || (result->domain == NULL)) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
}
- E_md4hash(cli->password ? cli->password : "", nt_hash);
- return true;
+
+ *presult = result;
+ return NT_STATUS_OK;
}
NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
}
result->auth_type = DCERPC_AUTH_TYPE_NONE;
- result->spnego_type = PIPE_AUTH_TYPE_SPNEGO_NONE;
result->auth_level = DCERPC_AUTH_LEVEL_NONE;
result->user_name = talloc_strdup(result, "");
return NT_STATUS_OK;
}
-static int cli_auth_ntlmssp_data_destructor(struct pipe_auth_data *auth)
-{
- TALLOC_FREE(auth->a_u.auth_ntlmssp_state);
- return 0;
-}
-
-static NTSTATUS rpccli_ntlmssp_bind_data(TALLOC_CTX *mem_ctx,
- enum dcerpc_AuthType auth_type,
- enum dcerpc_AuthLevel auth_level,
- const char *domain,
- const char *username,
- const char *password,
- struct pipe_auth_data **presult)
+static NTSTATUS rpccli_generic_bind_data(TALLOC_CTX *mem_ctx,
+ enum dcerpc_AuthType auth_type,
+ enum dcerpc_AuthLevel auth_level,
+ const char *server,
+ const char *target_service,
+ const char *domain,
+ const char *username,
+ const char *password,
+ enum credentials_use_kerberos use_kerberos,
+ struct netlogon_creds_CredentialState *creds,
+ struct pipe_auth_data **presult)
{
+ struct auth_generic_state *auth_generic_ctx;
struct pipe_auth_data *result;
NTSTATUS status;
goto fail;
}
- status = auth_ntlmssp_client_start(NULL,
- global_myname(),
- lp_workgroup(),
- lp_client_ntlmv2_auth(),
- &result->a_u.auth_ntlmssp_state);
+ status = auth_generic_client_prepare(result,
+ &auth_generic_ctx);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
- talloc_set_destructor(result, cli_auth_ntlmssp_data_destructor);
-
- status = auth_ntlmssp_set_username(result->a_u.auth_ntlmssp_state,
- username);
+ status = auth_generic_set_username(auth_generic_ctx, username);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
- status = auth_ntlmssp_set_domain(result->a_u.auth_ntlmssp_state,
- domain);
+ status = auth_generic_set_domain(auth_generic_ctx, domain);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
- status = auth_ntlmssp_set_password(result->a_u.auth_ntlmssp_state,
- password);
+ status = auth_generic_set_password(auth_generic_ctx, password);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
- /*
- * Turn off sign+seal to allow selected auth level to turn it back on.
- */
- auth_ntlmssp_and_flags(result->a_u.auth_ntlmssp_state,
- ~(NTLMSSP_NEGOTIATE_SIGN |
- NTLMSSP_NEGOTIATE_SEAL));
-
- if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
- auth_ntlmssp_or_flags(result->a_u.auth_ntlmssp_state,
- NTLMSSP_NEGOTIATE_SIGN);
- } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
- auth_ntlmssp_or_flags(result->a_u.auth_ntlmssp_state,
- NTLMSSP_NEGOTIATE_SEAL |
- NTLMSSP_NEGOTIATE_SIGN);
- }
-
- *presult = result;
- return NT_STATUS_OK;
-
- fail:
- TALLOC_FREE(result);
- return status;
-}
-
-NTSTATUS rpccli_schannel_bind_data(TALLOC_CTX *mem_ctx, const char *domain,
- enum dcerpc_AuthLevel auth_level,
- struct netlogon_creds_CredentialState *creds,
- struct pipe_auth_data **presult)
-{
- struct pipe_auth_data *result;
-
- result = talloc(mem_ctx, struct pipe_auth_data);
- if (result == NULL) {
- return NT_STATUS_NO_MEMORY;
+ status = gensec_set_target_service(auth_generic_ctx->gensec_security, target_service);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
}
- result->auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
- result->spnego_type = PIPE_AUTH_TYPE_SPNEGO_NONE;
- result->auth_level = auth_level;
-
- result->user_name = talloc_strdup(result, "");
- result->domain = talloc_strdup(result, domain);
- if ((result->user_name == NULL) || (result->domain == NULL)) {
+ status = gensec_set_target_hostname(auth_generic_ctx->gensec_security, server);
+ if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
- result->a_u.schannel_auth = talloc(result, struct schannel_state);
- if (result->a_u.schannel_auth == NULL) {
+ cli_credentials_set_kerberos_state(auth_generic_ctx->credentials, use_kerberos);
+ cli_credentials_set_netlogon_creds(auth_generic_ctx->credentials, creds);
+
+ status = auth_generic_client_start_by_authtype(auth_generic_ctx, auth_type, auth_level);
+ if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
- result->a_u.schannel_auth->state = SCHANNEL_STATE_START;
- result->a_u.schannel_auth->seq_num = 0;
- result->a_u.schannel_auth->initiator = true;
- result->a_u.schannel_auth->creds = netlogon_creds_copy(result, creds);
-
+ result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
+ talloc_free(auth_generic_ctx);
*presult = result;
return NT_STATUS_OK;
fail:
TALLOC_FREE(result);
- return NT_STATUS_NO_MEMORY;
+ return status;
}
/**
* Create an rpc pipe client struct, connecting to a tcp port.
*/
static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host,
+ const struct sockaddr_storage *ss_addr,
uint16_t port,
- const struct ndr_syntax_id *abstract_syntax,
+ const struct ndr_interface_table *table,
struct rpc_pipe_client **presult)
{
struct rpc_pipe_client *result;
NTSTATUS status;
int fd;
- result = TALLOC_ZERO_P(mem_ctx, struct rpc_pipe_client);
+ result = talloc_zero(mem_ctx, struct rpc_pipe_client);
if (result == NULL) {
return NT_STATUS_NO_MEMORY;
}
- result->abstract_syntax = *abstract_syntax;
- result->transfer_syntax = ndr_transfer_syntax;
+ result->abstract_syntax = table->syntax_id;
+ result->transfer_syntax = ndr_transfer_syntax_ndr;
result->desthost = talloc_strdup(result, host);
result->srv_name_slash = talloc_asprintf_strupper_m(
result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
- if (!resolve_name(host, &addr, 0, false)) {
- status = NT_STATUS_NOT_FOUND;
- goto fail;
+ if (ss_addr == NULL) {
+ if (!resolve_name(host, &addr, NBT_NAME_SERVER, false)) {
+ status = NT_STATUS_NOT_FOUND;
+ goto fail;
+ }
+ } else {
+ addr = *ss_addr;
}
- status = open_socket_out(&addr, port, 60, &fd);
+ status = open_socket_out(&addr, port, 60*1000, &fd);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
* target host.
*/
static NTSTATUS rpc_pipe_get_tcp_port(const char *host,
- const struct ndr_syntax_id *abstract_syntax,
+ const struct sockaddr_storage *addr,
+ const struct ndr_interface_table *table,
uint16_t *pport)
{
NTSTATUS status;
struct rpc_pipe_client *epm_pipe = NULL;
+ struct dcerpc_binding_handle *epm_handle = NULL;
struct pipe_auth_data *auth = NULL;
struct dcerpc_binding *map_binding = NULL;
struct dcerpc_binding *res_binding = NULL;
uint32_t max_towers = 1;
struct epm_twr_p_t towers;
TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ uint32_t result = 0;
if (pport == NULL) {
status = NT_STATUS_INVALID_PARAMETER;
goto done;
}
+ if (ndr_syntax_id_equal(&table->syntax_id,
+ &ndr_table_epmapper.syntax_id)) {
+ *pport = 135;
+ return NT_STATUS_OK;
+ }
+
/* open the connection to the endpoint mapper */
- status = rpc_pipe_open_tcp_port(tmp_ctx, host, 135,
- &ndr_table_epmapper.syntax_id,
+ status = rpc_pipe_open_tcp_port(tmp_ctx, host, addr, 135,
+ &ndr_table_epmapper,
&epm_pipe);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
+ epm_handle = epm_pipe->binding_handle;
status = rpccli_anon_bind_data(tmp_ctx, &auth);
if (!NT_STATUS_IS_OK(status)) {
/* create tower for asking the epmapper */
- map_binding = TALLOC_ZERO_P(tmp_ctx, struct dcerpc_binding);
+ map_binding = talloc_zero(tmp_ctx, struct dcerpc_binding);
if (map_binding == NULL) {
status = NT_STATUS_NO_MEMORY;
goto done;
}
map_binding->transport = NCACN_IP_TCP;
- map_binding->object = *abstract_syntax;
+ map_binding->object = table->syntax_id;
map_binding->host = host; /* needed? */
map_binding->endpoint = "0"; /* correct? needed? */
- map_tower = TALLOC_ZERO_P(tmp_ctx, struct epm_twr_t);
+ map_tower = talloc_zero(tmp_ctx, struct epm_twr_t);
if (map_tower == NULL) {
status = NT_STATUS_NO_MEMORY;
goto done;
/* allocate further parameters for the epm_Map call */
- res_towers = TALLOC_ARRAY(tmp_ctx, struct epm_twr_t, max_towers);
+ res_towers = talloc_array(tmp_ctx, struct epm_twr_t, max_towers);
if (res_towers == NULL) {
status = NT_STATUS_NO_MEMORY;
goto done;
}
towers.twr = res_towers;
- entry_handle = TALLOC_ZERO_P(tmp_ctx, struct policy_handle);
+ entry_handle = talloc_zero(tmp_ctx, struct policy_handle);
if (entry_handle == NULL) {
status = NT_STATUS_NO_MEMORY;
goto done;
/* ask the endpoint mapper for the port */
- status = rpccli_epm_Map(epm_pipe,
+ status = dcerpc_epm_Map(epm_handle,
tmp_ctx,
- CONST_DISCARD(struct GUID *,
- &(abstract_syntax->uuid)),
+ discard_const_p(struct GUID,
+ &(table->syntax_id.uuid)),
map_tower,
entry_handle,
max_towers,
&num_towers,
- &towers);
+ &towers,
+ &result);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
+ if (result != EPMAPPER_STATUS_OK) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
if (num_towers != 1) {
status = NT_STATUS_UNSUCCESSFUL;
goto done;
* host.
*/
NTSTATUS rpc_pipe_open_tcp(TALLOC_CTX *mem_ctx, const char *host,
- const struct ndr_syntax_id *abstract_syntax,
+ const struct sockaddr_storage *addr,
+ const struct ndr_interface_table *table,
struct rpc_pipe_client **presult)
{
NTSTATUS status;
uint16_t port = 0;
- status = rpc_pipe_get_tcp_port(host, abstract_syntax, &port);
+ status = rpc_pipe_get_tcp_port(host, addr, table, &port);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- return rpc_pipe_open_tcp_port(mem_ctx, host, port,
- abstract_syntax, presult);
+ return rpc_pipe_open_tcp_port(mem_ctx, host, addr, port,
+ table, presult);
}
/********************************************************************
Create a rpc pipe client struct, connecting to a unix domain socket
********************************************************************/
NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx, const char *socket_path,
- const struct ndr_syntax_id *abstract_syntax,
+ const struct ndr_interface_table *table,
struct rpc_pipe_client **presult)
{
struct rpc_pipe_client *result;
struct sockaddr_un addr;
NTSTATUS status;
int fd;
+ socklen_t salen;
result = talloc_zero(mem_ctx, struct rpc_pipe_client);
if (result == NULL) {
return NT_STATUS_NO_MEMORY;
}
- result->abstract_syntax = *abstract_syntax;
- result->transfer_syntax = ndr_transfer_syntax;
+ result->abstract_syntax = table->syntax_id;
+ result->transfer_syntax = ndr_transfer_syntax_ndr;
result->desthost = get_myname(result);
result->srv_name_slash = talloc_asprintf_strupper_m(
ZERO_STRUCT(addr);
addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
+ strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
+ salen = sizeof(struct sockaddr_un);
- if (sys_connect(fd, (struct sockaddr *)(void *)&addr) == -1) {
+ if (connect(fd, (struct sockaddr *)(void *)&addr, salen) == -1) {
DEBUG(0, ("connect(%s) failed: %s\n", socket_path,
strerror(errno)));
close(fd);
****************************************************************************/
static NTSTATUS rpc_pipe_open_np(struct cli_state *cli,
- const struct ndr_syntax_id *abstract_syntax,
+ const struct ndr_interface_table *table,
struct rpc_pipe_client **presult)
{
struct rpc_pipe_client *result;
return NT_STATUS_INVALID_HANDLE;
}
- result = TALLOC_ZERO_P(NULL, struct rpc_pipe_client);
+ result = talloc_zero(NULL, struct rpc_pipe_client);
if (result == NULL) {
return NT_STATUS_NO_MEMORY;
}
- result->abstract_syntax = *abstract_syntax;
- result->transfer_syntax = ndr_transfer_syntax;
- result->desthost = talloc_strdup(result, cli->desthost);
+ result->abstract_syntax = table->syntax_id;
+ result->transfer_syntax = ndr_transfer_syntax_ndr;
+ result->desthost = talloc_strdup(result, smbXcli_conn_remote_name(cli->conn));
result->srv_name_slash = talloc_asprintf_strupper_m(
result, "\\\\%s", result->desthost);
return NT_STATUS_NO_MEMORY;
}
- status = rpc_transport_np_init(result, cli, abstract_syntax,
+ status = rpc_transport_np_init(result, cli, table,
&result->transport);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(result);
static NTSTATUS cli_rpc_pipe_open(struct cli_state *cli,
enum dcerpc_transport_t transport,
- const struct ndr_syntax_id *interface,
+ const struct ndr_interface_table *table,
struct rpc_pipe_client **presult)
{
switch (transport) {
case NCACN_IP_TCP:
- return rpc_pipe_open_tcp(NULL, cli->desthost, interface,
- presult);
+ return rpc_pipe_open_tcp(NULL,
+ smbXcli_conn_remote_name(cli->conn),
+ smbXcli_conn_remote_sockaddr(cli->conn),
+ table, presult);
case NCACN_NP:
- return rpc_pipe_open_np(cli, interface, presult);
+ return rpc_pipe_open_np(cli, table, presult);
default:
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS cli_rpc_pipe_open_noauth_transport(struct cli_state *cli,
enum dcerpc_transport_t transport,
- const struct ndr_syntax_id *interface,
+ const struct ndr_interface_table *table,
struct rpc_pipe_client **presult)
{
struct rpc_pipe_client *result;
struct pipe_auth_data *auth;
NTSTATUS status;
- status = cli_rpc_pipe_open(cli, transport, interface, &result);
+ status = cli_rpc_pipe_open(cli, transport, table, &result);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
auth->user_name = talloc_strdup(auth, cli->user_name);
auth->domain = talloc_strdup(auth, cli->domain);
- auth->user_session_key = data_blob_talloc(auth,
- cli->user_session_key.data,
- cli->user_session_key.length);
+
+ if (transport == NCACN_NP) {
+ struct smbXcli_session *session;
+
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ session = cli->smb2.session;
+ } else {
+ session = cli->smb1.session;
+ }
+
+ status = smbXcli_session_application_key(session, auth,
+ &auth->transport_session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ auth->transport_session_key = data_blob_null;
+ }
+ }
if ((auth->user_name == NULL) || (auth->domain == NULL)) {
TALLOC_FREE(result);
status = rpc_pipe_bind(result, auth);
if (!NT_STATUS_IS_OK(status)) {
int lvl = 0;
- if (ndr_syntax_id_equal(interface,
+ if (ndr_syntax_id_equal(&table->syntax_id,
&ndr_table_dssetup.syntax_id)) {
/* non AD domains just don't have this pipe, avoid
* level 0 statement in that case - gd */
}
DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe "
"%s failed with error %s\n",
- get_pipe_name_from_syntax(talloc_tos(), interface),
+ table->name,
nt_errstr(status) ));
TALLOC_FREE(result);
return status;
DEBUG(10,("cli_rpc_pipe_open_noauth: opened pipe %s to machine "
"%s and bound anonymously.\n",
- get_pipe_name_from_syntax(talloc_tos(), interface),
- cli->desthost));
+ table->name,
+ result->desthost));
*presult = result;
return NT_STATUS_OK;
****************************************************************************/
NTSTATUS cli_rpc_pipe_open_noauth(struct cli_state *cli,
- const struct ndr_syntax_id *interface,
+ const struct ndr_interface_table *table,
struct rpc_pipe_client **presult)
{
return cli_rpc_pipe_open_noauth_transport(cli, NCACN_NP,
- interface, presult);
+ table, presult);
}
/****************************************************************************
- Open a named pipe to an SMB server and bind using NTLMSSP or SPNEGO NTLMSSP
+ Open a named pipe to an SMB server and bind using the mech specified
****************************************************************************/
-NTSTATUS cli_rpc_pipe_open_ntlmssp(struct cli_state *cli,
- const struct ndr_syntax_id *interface,
- enum dcerpc_transport_t transport,
- enum dcerpc_AuthLevel auth_level,
- const char *domain,
- const char *username,
- const char *password,
- struct rpc_pipe_client **presult)
+NTSTATUS cli_rpc_pipe_open_generic_auth(struct cli_state *cli,
+ const struct ndr_interface_table *table,
+ enum dcerpc_transport_t transport,
+ enum dcerpc_AuthType auth_type,
+ enum dcerpc_AuthLevel auth_level,
+ const char *server,
+ const char *domain,
+ const char *username,
+ const char *password,
+ struct rpc_pipe_client **presult)
{
struct rpc_pipe_client *result;
struct pipe_auth_data *auth = NULL;
- enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
+ const char *target_service = table->authservices->names[0];
+
NTSTATUS status;
- status = cli_rpc_pipe_open(cli, transport, interface, &result);
+ status = cli_rpc_pipe_open(cli, transport, table, &result);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = rpccli_ntlmssp_bind_data(result,
+ status = rpccli_generic_bind_data(result,
auth_type, auth_level,
- domain, username, password,
+ server, target_service,
+ domain, username, password,
+ CRED_AUTO_USE_KERBEROS,
+ NULL,
&auth);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("rpccli_ntlmssp_bind_data returned %s\n",
+ DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
nt_errstr(status)));
goto err;
}
status = rpc_pipe_bind(result, auth);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("cli_rpc_pipe_open_ntlmssp_internal: cli_rpc_pipe_bind failed with error %s\n",
+ DEBUG(0, ("cli_rpc_pipe_open_generic_auth: cli_rpc_pipe_bind failed with error %s\n",
nt_errstr(status) ));
goto err;
}
- DEBUG(10,("cli_rpc_pipe_open_ntlmssp_internal: opened pipe %s to "
- "machine %s and bound NTLMSSP as user %s\\%s.\n",
- get_pipe_name_from_syntax(talloc_tos(), interface),
- cli->desthost, domain, username ));
+ DEBUG(10,("cli_rpc_pipe_open_generic_auth: opened pipe %s to "
+ "machine %s and bound as user %s\\%s.\n", table->name,
+ result->desthost, domain, username));
*presult = result;
return NT_STATUS_OK;
****************************************************************************/
NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli,
- const struct ndr_syntax_id *interface,
+ const struct ndr_interface_table *table,
enum dcerpc_transport_t transport,
enum dcerpc_AuthLevel auth_level,
const char *domain,
struct netlogon_creds_CredentialState **pdc,
- struct rpc_pipe_client **presult)
+ struct rpc_pipe_client **_rpccli)
{
- struct rpc_pipe_client *result;
- struct pipe_auth_data *auth;
+ struct rpc_pipe_client *rpccli;
+ struct pipe_auth_data *rpcauth;
NTSTATUS status;
+ NTSTATUS result;
+ struct netlogon_creds_CredentialState save_creds;
+ struct netr_Authenticator auth;
+ struct netr_Authenticator return_auth;
+ union netr_Capabilities capabilities;
+ const char *target_service = table->authservices->names[0];
- status = cli_rpc_pipe_open(cli, transport, interface, &result);
+ status = cli_rpc_pipe_open(cli, transport, table, &rpccli);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = rpccli_schannel_bind_data(result, domain, auth_level,
- *pdc, &auth);
+ status = rpccli_generic_bind_data(rpccli,
+ DCERPC_AUTH_TYPE_SCHANNEL,
+ auth_level,
+ NULL,
+ target_service,
+ domain,
+ (*pdc)->computer_name,
+ NULL,
+ CRED_AUTO_USE_KERBEROS,
+ *pdc,
+ &rpcauth);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("rpccli_schannel_bind_data returned %s\n",
+ DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
nt_errstr(status)));
- TALLOC_FREE(result);
- return status;
- }
-
- status = rpc_pipe_bind(result, auth);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("cli_rpc_pipe_open_schannel_with_key: "
- "cli_rpc_pipe_bind failed with error %s\n",
- nt_errstr(status) ));
- TALLOC_FREE(result);
+ TALLOC_FREE(rpccli);
return status;
}
/*
* The credentials on a new netlogon pipe are the ones we are passed
* in - copy them over
+ *
+ * This may get overwritten... in rpc_pipe_bind()...
*/
- result->dc = netlogon_creds_copy(result, *pdc);
- if (result->dc == NULL) {
- TALLOC_FREE(result);
+ rpccli->dc = netlogon_creds_copy(rpccli, *pdc);
+ if (rpccli->dc == NULL) {
+ TALLOC_FREE(rpccli);
return NT_STATUS_NO_MEMORY;
}
- DEBUG(10,("cli_rpc_pipe_open_schannel_with_key: opened pipe %s to machine %s "
- "for domain %s and bound using schannel.\n",
- get_pipe_name_from_syntax(talloc_tos(), interface),
- cli->desthost, domain ));
-
- *presult = result;
- return NT_STATUS_OK;
-}
-
-/****************************************************************************
- Open a named pipe to an SMB server and bind using krb5 (bind type 16).
- The idea is this can be called with service_princ, username and password all
- NULL so long as the caller has a TGT.
- ****************************************************************************/
-
-NTSTATUS cli_rpc_pipe_open_krb5(struct cli_state *cli,
- const struct ndr_syntax_id *interface,
- enum dcerpc_transport_t transport,
- enum dcerpc_AuthLevel auth_level,
- const char *server,
- const char *username,
- const char *password,
- struct rpc_pipe_client **presult)
-{
- struct rpc_pipe_client *result;
- struct pipe_auth_data *auth;
- NTSTATUS status;
-
- status = cli_rpc_pipe_open(cli, transport, interface, &result);
+ status = rpc_pipe_bind(rpccli, rpcauth);
if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("cli_rpc_pipe_open_schannel_with_key: "
+ "cli_rpc_pipe_bind failed with error %s\n",
+ nt_errstr(status) ));
+ TALLOC_FREE(rpccli);
return status;
}
- auth = talloc(result, struct pipe_auth_data);
- if (auth == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto err_out;
+ if (!ndr_syntax_id_equal(&table->syntax_id, &ndr_table_netlogon.syntax_id)) {
+ goto done;
}
- auth->auth_type = DCERPC_AUTH_TYPE_KRB5;
- auth->auth_level = auth_level;
- if (!username) {
- username = "";
- }
- auth->user_name = talloc_strdup(auth, username);
- if (!auth->user_name) {
- status = NT_STATUS_NO_MEMORY;
- goto err_out;
- }
+ save_creds = *rpccli->dc;
+ ZERO_STRUCT(return_auth);
+ ZERO_STRUCT(capabilities);
- /* Fixme, should we fetch/set the Realm ? */
- auth->domain = talloc_strdup(auth, "");
- if (!auth->domain) {
- status = NT_STATUS_NO_MEMORY;
- goto err_out;
- }
+ netlogon_creds_client_authenticator(&save_creds, &auth);
- status = gse_init_client(auth,
- (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY),
- (auth_level == DCERPC_AUTH_LEVEL_PRIVACY),
- NULL, server, "cifs", username, password,
- GSS_C_DCE_STYLE, &auth->a_u.gssapi_state);
+ status = dcerpc_netr_LogonGetCapabilities(rpccli->binding_handle,
+ talloc_tos(),
+ rpccli->srv_name_slash,
+ save_creds.computer_name,
+ &auth, &return_auth,
+ 1, &capabilities,
+ &result);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ if (save_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ DEBUG(5, ("AES was negotiated and the error was %s - "
+ "downgrade detected\n",
+ nt_errstr(status)));
+ TALLOC_FREE(rpccli);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("gse_init_client returned %s\n",
+ /* This is probably an old Samba Version */
+ DEBUG(5, ("We are checking against an NT or old Samba - %s\n",
nt_errstr(status)));
- goto err_out;
+ goto done;
}
- status = rpc_pipe_bind(result, auth);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("cli_rpc_pipe_bind failed with error %s\n",
+ DEBUG(0, ("dcerpc_netr_LogonGetCapabilities failed with %s\n",
nt_errstr(status)));
- goto err_out;
+ TALLOC_FREE(rpccli);
+ return status;
}
- *presult = result;
- return NT_STATUS_OK;
-
-err_out:
- TALLOC_FREE(result);
- return status;
-}
-
-NTSTATUS cli_rpc_pipe_open_spnego_krb5(struct cli_state *cli,
- const struct ndr_syntax_id *interface,
- enum dcerpc_transport_t transport,
- enum dcerpc_AuthLevel auth_level,
- const char *server,
- const char *username,
- const char *password,
- struct rpc_pipe_client **presult)
-{
- struct rpc_pipe_client *result;
- struct pipe_auth_data *auth;
- NTSTATUS status;
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
+ if (save_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ /* This means AES isn't supported. */
+ DEBUG(5, ("AES was negotiated and the result was %s - "
+ "downgrade detected\n",
+ nt_errstr(result)));
+ TALLOC_FREE(rpccli);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
- status = cli_rpc_pipe_open(cli, transport, interface, &result);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ /* This is probably an old Windows version */
+ DEBUG(5, ("We are checking against an win2k3 or Samba - %s\n",
+ nt_errstr(result)));
+ goto done;
}
- auth = talloc(result, struct pipe_auth_data);
- if (auth == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto err_out;
+ /*
+ * We need to check the credential state here, cause win2k3 and earlier
+ * returns NT_STATUS_NOT_IMPLEMENTED
+ */
+ if (!netlogon_creds_client_check(&save_creds, &return_auth.cred)) {
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("cli_rpc_pipe_open_schannel_with_key: server %s "
+ "replied with bad credential\n",
+ rpccli->desthost));
+ TALLOC_FREE(rpccli);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
- auth->auth_type = DCERPC_AUTH_TYPE_SPNEGO;
- auth->auth_level = auth_level;
- /* compat */
- auth->spnego_type = PIPE_AUTH_TYPE_SPNEGO_KRB5;
+ *rpccli->dc = save_creds;
- if (!username) {
- username = "";
- }
- auth->user_name = talloc_strdup(auth, username);
- if (!auth->user_name) {
- status = NT_STATUS_NO_MEMORY;
- goto err_out;
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("dcerpc_netr_LogonGetCapabilities failed with %s\n",
+ nt_errstr(result)));
+ TALLOC_FREE(rpccli);
+ return result;
}
- /* Fixme, should we fetch/set the Realm ? */
- auth->domain = talloc_strdup(auth, "");
- if (!auth->domain) {
- status = NT_STATUS_NO_MEMORY;
- goto err_out;
+ if (!(save_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES)) {
+ /* This means AES isn't supported. */
+ DEBUG(5, ("AES is not negotiated, but netr_LogonGetCapabilities "
+ "was OK - downgrade detected\n"));
+ TALLOC_FREE(rpccli);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
- status = spnego_gssapi_init_client(auth,
- (auth->auth_level ==
- DCERPC_AUTH_LEVEL_INTEGRITY),
- (auth->auth_level ==
- DCERPC_AUTH_LEVEL_PRIVACY),
- true,
- NULL, server, "cifs",
- username, password,
- &auth->a_u.spnego_state);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("spnego_init_client returned %s\n",
- nt_errstr(status)));
- goto err_out;
+ if (save_creds.negotiate_flags != capabilities.server_capabilities) {
+ DEBUG(0, ("The client capabilities don't match the server "
+ "capabilities: local[0x%08X] remote[0x%08X]\n",
+ save_creds.negotiate_flags,
+ capabilities.server_capabilities));
+ TALLOC_FREE(rpccli);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
- status = rpc_pipe_bind(result, auth);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("cli_rpc_pipe_bind failed with error %s\n",
- nt_errstr(status)));
- goto err_out;
- }
+done:
+ DEBUG(10,("cli_rpc_pipe_open_schannel_with_key: opened pipe %s to machine %s "
+ "for domain %s and bound using schannel.\n",
+ table->name,
+ rpccli->desthost, domain));
- *presult = result;
+ *_rpccli = rpccli;
return NT_STATUS_OK;
-
-err_out:
- TALLOC_FREE(result);
- return status;
}
-NTSTATUS cli_rpc_pipe_open_spnego_ntlmssp(struct cli_state *cli,
- const struct ndr_syntax_id *interface,
- enum dcerpc_transport_t transport,
- enum dcerpc_AuthLevel auth_level,
- const char *domain,
- const char *username,
- const char *password,
- struct rpc_pipe_client **presult)
+NTSTATUS cli_rpc_pipe_open_spnego(struct cli_state *cli,
+ const struct ndr_interface_table *table,
+ enum dcerpc_transport_t transport,
+ const char *oid,
+ enum dcerpc_AuthLevel auth_level,
+ const char *server,
+ const char *domain,
+ const char *username,
+ const char *password,
+ struct rpc_pipe_client **presult)
{
struct rpc_pipe_client *result;
- struct pipe_auth_data *auth;
+ struct pipe_auth_data *auth = NULL;
+ const char *target_service = table->authservices->names[0];
+
NTSTATUS status;
+ enum credentials_use_kerberos use_kerberos;
- status = cli_rpc_pipe_open(cli, transport, interface, &result);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- auth = talloc(result, struct pipe_auth_data);
- if (auth == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto err_out;
- }
- auth->auth_type = DCERPC_AUTH_TYPE_SPNEGO;
- auth->auth_level = auth_level;
-
- if (!username) {
- username = "";
- }
- auth->user_name = talloc_strdup(auth, username);
- if (!auth->user_name) {
- status = NT_STATUS_NO_MEMORY;
- goto err_out;
+ if (strcmp(oid, GENSEC_OID_KERBEROS5) == 0) {
+ use_kerberos = CRED_MUST_USE_KERBEROS;
+ } else if (strcmp(oid, GENSEC_OID_NTLMSSP) == 0) {
+ use_kerberos = CRED_DONT_USE_KERBEROS;
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
}
- if (!domain) {
- domain = "";
- }
- auth->domain = talloc_strdup(auth, domain);
- if (!auth->domain) {
- status = NT_STATUS_NO_MEMORY;
- goto err_out;
+ status = cli_rpc_pipe_open(cli, transport, table, &result);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
- status = spnego_ntlmssp_init_client(auth,
- (auth->auth_level ==
- DCERPC_AUTH_LEVEL_INTEGRITY),
- (auth->auth_level ==
- DCERPC_AUTH_LEVEL_PRIVACY),
- true,
- domain, username, password,
- &auth->a_u.spnego_state);
+ status = rpccli_generic_bind_data(result,
+ DCERPC_AUTH_TYPE_SPNEGO, auth_level,
+ server, target_service,
+ domain, username, password,
+ use_kerberos, NULL,
+ &auth);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("spnego_init_client returned %s\n",
+ DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
nt_errstr(status)));
- goto err_out;
+ goto err;
}
status = rpc_pipe_bind(result, auth);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("cli_rpc_pipe_bind failed with error %s\n",
- nt_errstr(status)));
- goto err_out;
+ DEBUG(0, ("cli_rpc_pipe_open_spnego: cli_rpc_pipe_bind failed with error %s\n",
+ nt_errstr(status) ));
+ goto err;
}
+ DEBUG(10,("cli_rpc_pipe_open_spnego: opened pipe %s to "
+ "machine %s.\n", table->name,
+ result->desthost));
+
*presult = result;
return NT_STATUS_OK;
-err_out:
+ err:
+
TALLOC_FREE(result);
return status;
}
struct rpc_pipe_client *cli,
DATA_BLOB *session_key)
{
- struct pipe_auth_data *a = cli->auth;
+ NTSTATUS status;
+ struct pipe_auth_data *a;
+ struct gensec_security *gensec_security;
DATA_BLOB sk = data_blob_null;
bool make_dup = false;
return NT_STATUS_INVALID_PARAMETER;
}
- if (!cli->auth) {
+ a = cli->auth;
+
+ if (a == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
switch (cli->auth->auth_type) {
- case DCERPC_AUTH_TYPE_SCHANNEL:
- sk = data_blob_const(a->a_u.schannel_auth->creds->session_key,
- 16);
- make_dup = true;
- break;
case DCERPC_AUTH_TYPE_SPNEGO:
- sk = spnego_get_session_key(mem_ctx, a->a_u.spnego_state);
- make_dup = false;
- break;
case DCERPC_AUTH_TYPE_NTLMSSP:
- sk = auth_ntlmssp_get_session_key(a->a_u.auth_ntlmssp_state);
- make_dup = true;
- break;
case DCERPC_AUTH_TYPE_KRB5:
- sk = gse_get_session_key(mem_ctx, a->a_u.gssapi_state);
+ gensec_security = talloc_get_type_abort(a->auth_ctx,
+ struct gensec_security);
+ status = gensec_session_key(gensec_security, mem_ctx, &sk);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
make_dup = false;
break;
+ case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
case DCERPC_AUTH_TYPE_NONE:
- sk = data_blob_const(a->user_session_key.data,
- a->user_session_key.length);
+ sk = data_blob_const(a->transport_session_key.data,
+ a->transport_session_key.length);
make_dup = true;
break;
default:
}
if (make_dup) {
- *session_key = data_blob_dup_talloc(mem_ctx, &sk);
+ *session_key = data_blob_dup_talloc(mem_ctx, sk);
} else {
*session_key = sk;
}