*
* 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 2 of the License, or
+ * 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,
data = (unsigned char *)(prs_data_p(current_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN);
data_len = (size_t)(prhdr->frag_len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN - RPC_HDR_AUTH_LEN - auth_len);
- full_packet_data = prs_data_p(current_pdu);
+ full_packet_data = (unsigned char *)prs_data_p(current_pdu);
full_packet_data_len = prhdr->frag_len - auth_len;
/* Pull the auth header and the following data into a blob. */
return NT_STATUS_BUFFER_TOO_SMALL;
}
- auth_blob.data = prs_data_p(current_pdu) + prs_offset(current_pdu);
+ auth_blob.data = (unsigned char *)prs_data_p(current_pdu) + prs_offset(current_pdu);
auth_blob.length = auth_len;
switch (cli->auth.auth_level) {
DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault code %s received from remote machine %s "
"pipe %s fnum 0x%x!\n",
- nt_errstr(fault_resp.status),
+ dcerpc_errstr(NT_STATUS_V(fault_resp.status)),
cli->cli->desthost,
cli->pipe_name,
(unsigned int)cli->fnum));
char *rparam = NULL;
uint32 rparam_len = 0;
uint16 setup[2];
- char *pdata = data ? prs_data_p(data) : NULL;
- uint32 data_len = data ? prs_offset(data) : 0;
+ char *pdata = prs_data_p(data);
+ uint32 data_len = prs_offset(data);
char *prdata = NULL;
uint32 rdata_len = 0;
uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : RPC_MAX_PDU_FRAG_LEN;
(unsigned int)cli->fnum,
cli_errstr(cli->cli)));
ret = cli_get_nt_error(cli->cli);
+ SAFE_FREE(rparam);
+ SAFE_FREE(prdata);
goto err;
}
#ifdef HAVE_KRB5
int ret;
struct kerberos_auth_struct *a = cli->auth.a_u.kerberos_auth;
- DATA_BLOB tkt = data_blob(NULL, 0);
- DATA_BLOB tkt_wrapped = data_blob(NULL, 0);
+ DATA_BLOB tkt = data_blob_null;
+ DATA_BLOB tkt_wrapped = data_blob_null;
/* We may change the pad length before marshalling. */
init_rpc_hdr_auth(pauth_out, RPC_KRB5_AUTH_TYPE, (int)auth_level, 0, 1);
/* Create the ticket for the service principal and return it in a gss-api wrapped blob. */
ret = cli_krb5_get_ticket(a->service_principal, 0, &tkt,
- &a->session_key, (uint32)AP_OPTS_MUTUAL_REQUIRED);
+ &a->session_key, (uint32)AP_OPTS_MUTUAL_REQUIRED, NULL, NULL);
if (ret) {
DEBUG(1,("create_krb5_auth_bind_req: cli_krb5_get_ticket for principal %s "
}
DEBUG(5, ("create_krb5_auth_bind_req: Created krb5 GSS blob :\n"));
- dump_data(5, (const char *)tkt_wrapped.data, tkt_wrapped.length);
+ dump_data(5, tkt_wrapped.data, tkt_wrapped.length);
data_blob_free(&tkt_wrapped);
return NT_STATUS_OK;
prs_struct *auth_data)
{
NTSTATUS nt_status;
- DATA_BLOB null_blob = data_blob(NULL, 0);
- DATA_BLOB request = data_blob(NULL, 0);
- DATA_BLOB spnego_msg = data_blob(NULL, 0);
+ DATA_BLOB null_blob = data_blob_null;
+ DATA_BLOB request = data_blob_null;
+ DATA_BLOB spnego_msg = data_blob_null;
/* We may change the pad length before marshalling. */
init_rpc_hdr_auth(pauth_out, RPC_SPNEGO_AUTH_TYPE, (int)auth_level, 0, 1);
}
DEBUG(5, ("create_spnego_ntlmssp_auth_rpc_bind_req: NTLMSSP Negotiate:\n"));
- dump_data(5, (const char *)spnego_msg.data, spnego_msg.length);
+ dump_data(5, spnego_msg.data, spnego_msg.length);
data_blob_free(&spnego_msg);
return NT_STATUS_OK;
prs_struct *auth_data)
{
NTSTATUS nt_status;
- DATA_BLOB null_blob = data_blob(NULL, 0);
- DATA_BLOB request = data_blob(NULL, 0);
+ DATA_BLOB null_blob = data_blob_null;
+ DATA_BLOB request = data_blob_null;
/* We may change the pad length before marshalling. */
init_rpc_hdr_auth(pauth_out, RPC_NTLMSSP_AUTH_TYPE, (int)auth_level, 0, 1);
}
DEBUG(5, ("create_ntlmssp_auth_rpc_bind_req: NTLMSSP Negotiate:\n"));
- dump_data(5, (const char *)request.data, request.length);
+ dump_data(5, request.data, request.length);
data_blob_free(&request);
return NT_STATUS_OK;
Creates the internals of a DCE/RPC bind request or alter context PDU.
********************************************************************/
-static NTSTATUS create_bind_or_alt_ctx_internal(uint8 pkt_type,
+static NTSTATUS create_bind_or_alt_ctx_internal(enum RPC_PKT_TYPE pkt_type,
prs_struct *rpc_out,
uint32 rpc_call_id,
RPC_IFACE *abstract,
if(auth_len != 0) {
if (ss_padding_len) {
- unsigned char pad[8];
+ char pad[8];
memset(pad, '\0', 8);
if (!prs_copy_data_in(rpc_out, pad, ss_padding_len)) {
DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall padding.\n"));
{
RPC_HDR_AUTH auth_info;
NTSTATUS status;
- DATA_BLOB auth_blob = data_blob(NULL, 0);
+ DATA_BLOB auth_blob = data_blob_null;
uint16 data_and_pad_len = prs_offset(outgoing_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
if (!cli->auth.a_u.ntlmssp_state) {
case PIPE_AUTH_LEVEL_PRIVACY:
/* Data portion is encrypted. */
status = ntlmssp_seal_packet(cli->auth.a_u.ntlmssp_state,
- prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
+ (unsigned char *)prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
data_and_pad_len,
- prs_data_p(outgoing_pdu),
+ (unsigned char *)prs_data_p(outgoing_pdu),
(size_t)prs_offset(outgoing_pdu),
&auth_blob);
if (!NT_STATUS_IS_OK(status)) {
case PIPE_AUTH_LEVEL_INTEGRITY:
/* Data is signed. */
status = ntlmssp_sign_packet(cli->auth.a_u.ntlmssp_state,
- prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
+ (unsigned char *)prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN,
data_and_pad_len,
- prs_data_p(outgoing_pdu),
+ (unsigned char *)prs_data_p(outgoing_pdu),
(size_t)prs_offset(outgoing_pdu),
&auth_blob);
if (!NT_STATUS_IS_OK(status)) {
/* Finally marshall the blob. */
- if (!prs_copy_data_in(outgoing_pdu, auth_blob.data, NTLMSSP_SIG_SIZE)) {
+ if (!prs_copy_data_in(outgoing_pdu, (const char *)auth_blob.data, NTLMSSP_SIG_SIZE)) {
DEBUG(0,("add_ntlmssp_auth_footer: failed to add %u bytes auth blob.\n",
(unsigned int)NTLMSSP_SIG_SIZE));
data_blob_free(&auth_blob);
}
DEBUG(5,("Bind Abstract Syntax: "));
- dump_data(5, (char*)&pipe_names[pipe_idx].abstr_syntax,
+ dump_data(5, (uint8 *)&pipe_names[pipe_idx].abstr_syntax,
sizeof(pipe_names[pipe_idx].abstr_syntax));
DEBUG(5,("Bind Transfer Syntax: "));
- dump_data(5, (char*)&pipe_names[pipe_idx].trans_syntax,
+ dump_data(5, (uint8 *)&pipe_names[pipe_idx].trans_syntax,
sizeof(pipe_names[pipe_idx].trans_syntax));
/* copy the required syntaxes out so we can do the right bind */
enum pipe_auth_type auth_type,
enum pipe_auth_level auth_level)
{
- DATA_BLOB server_response = data_blob(NULL,0);
- DATA_BLOB client_reply = data_blob(NULL,0);
+ DATA_BLOB server_response = data_blob_null;
+ DATA_BLOB client_reply = data_blob_null;
RPC_HDR_AUTH hdr_auth;
NTSTATUS nt_status;
prs_struct rpc_out;
enum pipe_auth_type auth_type,
enum pipe_auth_level auth_level)
{
- DATA_BLOB server_spnego_response = data_blob(NULL,0);
- DATA_BLOB server_ntlm_response = data_blob(NULL,0);
- DATA_BLOB client_reply = data_blob(NULL,0);
- DATA_BLOB tmp_blob = data_blob(NULL, 0);
+ DATA_BLOB server_spnego_response = data_blob_null;
+ DATA_BLOB server_ntlm_response = data_blob_null;
+ DATA_BLOB client_reply = data_blob_null;
+ DATA_BLOB tmp_blob = data_blob_null;
RPC_HDR_AUTH hdr_auth;
NTSTATUS nt_status;
prs_struct rpc_out;
tmp_blob = spnego_gen_auth(client_reply);
data_blob_free(&client_reply);
client_reply = tmp_blob;
- tmp_blob = data_blob(NULL,0); /* Ensure it's safe to free this just in case. */
+ tmp_blob = data_blob_null; /* Ensure it's safe to free this just in case. */
/* Now prepare the alter context pdu. */
prs_init(&rpc_out, 0, prs_get_mem_context(rbuf), MARSHALL);
prs_copy_data_out((char *)server_spnego_response.data, rbuf, phdr->auth_len);
/* Check we got a valid auth response. */
- if (!spnego_parse_auth_response(server_spnego_response, NT_STATUS_OK, &tmp_blob)) {
+ if (!spnego_parse_auth_response(server_spnego_response, NT_STATUS_OK, OID_NTLMSSP, &tmp_blob)) {
data_blob_free(&server_spnego_response);
data_blob_free(&tmp_blob);
return NT_STATUS_INVALID_PARAMETER;
return NT_STATUS_INVALID_INFO_CLASS;
}
+ /* For NTLMSSP ensure the server gave us the auth_level we wanted. */
+ if (auth_type == PIPE_AUTH_TYPE_NTLMSSP || auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
+ if (auth_level == PIPE_AUTH_LEVEL_INTEGRITY) {
+ if (!(cli->auth.a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
+ DEBUG(0,("cli_finish_bind_auth: requested NTLMSSSP signing and server refused.\n"));
+ prs_mem_free(&rbuf);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ if (auth_level == PIPE_AUTH_LEVEL_INTEGRITY) {
+ if (!(cli->auth.a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
+ DEBUG(0,("cli_finish_bind_auth: requested NTLMSSSP sealing and server refused.\n"));
+ prs_mem_free(&rbuf);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
/* Pipe is bound - set up auth_type and auth_level data. */
cli->auth.auth_type = auth_type;
/****************************************************************************
Open a named pipe over SMB to a remote server.
+ *
+ * CAVEAT CALLER OF THIS FUNCTION:
+ * The returned rpc_pipe_client saves a copy of the cli_state cli pointer,
+ * so be sure that this function is called AFTER any structure (vs pointer)
+ * assignment of the cli. In particular, libsmbclient does structure
+ * assignments of cli, which invalidates the data in the returned
+ * rpc_pipe_client if this function is called before the structure assignment
+ * of cli.
+ *
****************************************************************************/
static struct rpc_pipe_client *cli_rpc_pipe_open(struct cli_state *cli, int pipe_idx, NTSTATUS *perr)
*perr = NT_STATUS_NO_MEMORY;
+ /* sanity check to protect against crashes */
+
+ if ( !cli ) {
+ *perr = NT_STATUS_INVALID_HANDLE;
+ return NULL;
+ }
+
/* The pipe name index must fall within our array */
SMB_ASSERT((pipe_idx >= 0) && (pipe_idx < PI_MAX_PIPES));
fnum = cli_nt_create(cli, result->pipe_name, DESIRED_ACCESS_PIPE);
if (fnum == -1) {
- DEBUG(0,("cli_rpc_pipe_open: cli_nt_create failed on pipe %s "
+ DEBUG(1,("cli_rpc_pipe_open: cli_nt_create failed on pipe %s "
"to machine %s. Error was %s\n",
result->pipe_name, cli->desthost,
cli_errstr(cli)));
*perr = rpc_pipe_bind(result, PIPE_AUTH_TYPE_NONE, PIPE_AUTH_LEVEL_NONE);
if (!NT_STATUS_IS_OK(*perr)) {
- DEBUG(0, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe %s failed with error %s\n",
+ int lvl = 0;
+ if (pipe_idx == PI_LSARPC_DS) {
+ /* non AD domains just don't have this pipe, avoid
+ * level 0 statement in that case - gd */
+ lvl = 3;
+ }
+ DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe %s failed with error %s\n",
cli_get_pipe_name(pipe_idx), nt_errstr(*perr) ));
cli_rpc_pipe_close(result);
return NULL;
/****************************************************************************
Open a netlogon pipe and get the schannel session key.
+ Now exposed to external callers.
****************************************************************************/
-static struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli,
+struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli,
const char *domain,
+ uint32 *pneg_flags,
NTSTATUS *perr)
{
- uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS|NETLOGON_NEG_SCHANNEL;
struct rpc_pipe_client *netlogon_pipe = NULL;
uint32 sec_chan_type = 0;
- char machine_pwd[16];
+ unsigned char machine_pwd[16];
fstring machine_account;
netlogon_pipe = cli_rpc_pipe_open_noauth(cli, PI_NETLOGON, perr);
return NULL;
}
- if ( IS_DC ) {
+ /* A DC should use DOMAIN$ as its account name.
+ A member server can only use it's machine name since it
+ does not have an account in a trusted domain.
+
+ We don't check the domain against lp_workgroup() here since
+ 'net ads join' has to continue to work with only the realm
+ specified in smb.conf. -- jerry */
+
+ if ( IS_DC && !strequal(domain, lp_workgroup()) && lp_allow_trusted_domains()) {
fstrcpy( machine_account, lp_workgroup() );
} else {
- /* Hmmm. Is this correct for trusted domains when we're a member server ? JRA. */
- if (strequal(domain, lp_workgroup())) {
- fstrcpy(machine_account, global_myname());
- } else {
- fstrcpy(machine_account, domain);
- }
+ fstrcpy(machine_account, global_myname());
}
*perr = rpccli_netlogon_setup_creds(netlogon_pipe,
- cli->desthost,
- domain,
- machine_account,
+ cli->desthost, /* server name */
+ domain, /* domain */
+ global_myname(), /* client name */
+ machine_account, /* machine account name */
machine_pwd,
sec_chan_type,
- &neg_flags);
+ pneg_flags);
if (!NT_STATUS_IS_OK(*perr)) {
DEBUG(3,("get_schannel_session_key: rpccli_netlogon_setup_creds "
- "failed with result %s\n",
- nt_errstr(*perr) ));
+ "failed with result %s to server %s, domain %s, machine account %s.\n",
+ nt_errstr(*perr), cli->desthost, domain, machine_account ));
cli_rpc_pipe_close(netlogon_pipe);
return NULL;
}
- if ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0) {
+ if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) {
DEBUG(3, ("get_schannel_session_key: Server %s did not offer schannel\n",
cli->desthost));
cli_rpc_pipe_close(netlogon_pipe);
return result;
}
+/****************************************************************************
+ Open a named pipe to an SMB server and bind using schannel (bind type 68).
+ Fetch the session key ourselves using a temporary netlogon pipe. This
+ version uses an ntlmssp auth bound netlogon pipe to get the key.
+ ****************************************************************************/
+
+static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_state *cli,
+ const char *domain,
+ const char *username,
+ const char *password,
+ uint32 *pneg_flags,
+ NTSTATUS *perr)
+{
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+ uint32 sec_chan_type = 0;
+ unsigned char machine_pwd[16];
+ fstring machine_account;
+
+ netlogon_pipe = cli_rpc_pipe_open_spnego_ntlmssp(cli, PI_NETLOGON, PIPE_AUTH_LEVEL_PRIVACY, domain, username, password, perr);
+ if (!netlogon_pipe) {
+ return NULL;
+ }
+
+ /* Get the machine account credentials from secrets.tdb. */
+ if (!get_trust_pw(domain, machine_pwd, &sec_chan_type)) {
+ DEBUG(0, ("get_schannel_session_key_auth_ntlmssp: could not fetch "
+ "trust account password for domain '%s'\n",
+ domain));
+ cli_rpc_pipe_close(netlogon_pipe);
+ *perr = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ return NULL;
+ }
+
+ /* if we are a DC and this is a trusted domain, then we need to use our
+ domain name in the net_req_auth2() request */
+
+ if ( IS_DC && !strequal(domain, lp_workgroup()) && lp_allow_trusted_domains()) {
+ fstrcpy( machine_account, lp_workgroup() );
+ } else {
+ /* Hmmm. Is this correct for trusted domains when we're a member server ? JRA. */
+ if (strequal(domain, lp_workgroup())) {
+ fstrcpy(machine_account, global_myname());
+ } else {
+ fstrcpy(machine_account, domain);
+ }
+ }
+
+ *perr = rpccli_netlogon_setup_creds(netlogon_pipe,
+ cli->desthost, /* server name */
+ domain, /* domain */
+ global_myname(), /* client name */
+ machine_account, /* machine account name */
+ machine_pwd,
+ sec_chan_type,
+ pneg_flags);
+
+ if (!NT_STATUS_IS_OK(*perr)) {
+ DEBUG(3,("get_schannel_session_key_auth_ntlmssp: rpccli_netlogon_setup_creds "
+ "failed with result %s\n",
+ nt_errstr(*perr) ));
+ cli_rpc_pipe_close(netlogon_pipe);
+ return NULL;
+ }
+
+ if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) {
+ DEBUG(3, ("get_schannel_session_key_auth_ntlmssp: Server %s did not offer schannel\n",
+ cli->desthost));
+ cli_rpc_pipe_close(netlogon_pipe);
+ *perr = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ return NULL;
+ }
+
+ return netlogon_pipe;
+}
+
+/****************************************************************************
+ Open a named pipe to an SMB server and bind using schannel (bind type 68).
+ Fetch the session key ourselves using a temporary netlogon pipe. This version
+ uses an ntlmssp bind to get the session key.
+ ****************************************************************************/
+
+struct rpc_pipe_client *cli_rpc_pipe_open_ntlmssp_auth_schannel(struct cli_state *cli,
+ int pipe_idx,
+ enum pipe_auth_level auth_level,
+ const char *domain,
+ const char *username,
+ const char *password,
+ NTSTATUS *perr)
+{
+ uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS|NETLOGON_NEG_SCHANNEL;
+ struct rpc_pipe_client *netlogon_pipe = NULL;
+ struct rpc_pipe_client *result = NULL;
+
+ netlogon_pipe = get_schannel_session_key_auth_ntlmssp(cli, domain, username,
+ password, &neg_flags, perr);
+ if (!netlogon_pipe) {
+ DEBUG(0,("cli_rpc_pipe_open_ntlmssp_auth_schannel: failed to get schannel session "
+ "key from server %s for domain %s.\n",
+ cli->desthost, domain ));
+ return NULL;
+ }
+
+ result = cli_rpc_pipe_open_schannel_with_key(cli, pipe_idx,
+ auth_level,
+ domain, netlogon_pipe->dc, perr);
+
+ /* Now we've bound using the session key we can close the netlog pipe. */
+ cli_rpc_pipe_close(netlogon_pipe);
+
+ return result;
+}
+
/****************************************************************************
Open a named pipe to an SMB server and bind using schannel (bind type 68).
Fetch the session key ourselves using a temporary netlogon pipe.
const char *domain,
NTSTATUS *perr)
{
+ uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS|NETLOGON_NEG_SCHANNEL;
struct rpc_pipe_client *netlogon_pipe = NULL;
struct rpc_pipe_client *result = NULL;
- netlogon_pipe = get_schannel_session_key(cli, domain, perr);
+ netlogon_pipe = get_schannel_session_key(cli, domain, &neg_flags, perr);
if (!netlogon_pipe) {
DEBUG(0,("cli_rpc_pipe_open_schannel: failed to get schannel session "
"key from server %s for domain %s.\n",
return result;
}
+#ifdef HAVE_KRB5
+
/****************************************************************************
Free function for the kerberos spcific data.
****************************************************************************/
data_blob_free(&a->a_u.kerberos_auth->session_key);
}
+#endif
+
/****************************************************************************
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
return NULL;
}
- /* Default service principal is "host/server@realm" */
+ /* Default service principal is "desthost$@realm" */
if (!service_princ) {
- service_princ = talloc_asprintf(result->mem_ctx, "host/%s@%s",
+ service_princ = talloc_asprintf(result->mem_ctx, "%s$@%s",
cli->desthost, lp_realm() );
if (!service_princ) {
cli_rpc_pipe_close(result);
/* Only get a new TGT if username/password are given. */
if (username && password) {
- int ret = kerberos_kinit_password(username, password, 0, NULL, NULL);
+ int ret = kerberos_kinit_password(username, password, 0, NULL);
if (ret) {
cli_rpc_pipe_close(result);
return NULL;
Close an open named pipe over SMB. Free any authentication data.
****************************************************************************/
-void cli_rpc_pipe_close(struct rpc_pipe_client *cli)
+ void cli_rpc_pipe_close(struct rpc_pipe_client *cli)
{
if (!cli_close(cli->cli, cli->fnum)) {
DEBUG(0,("cli_rpc_pipe_close: cli_close failed on pipe %s "