*
* 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,
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,
{
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) {
}
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;
unsigned char machine_pwd[16];
return NULL;
}
+ /* 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,
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 "
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);
const char *domain,
const char *username,
const char *password,
+ 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;
unsigned char machine_pwd[16];
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_auth_ntlmssp: rpccli_netlogon_setup_creds "
return NULL;
}
- if ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0) {
+ 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);
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, perr);
+ 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",
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 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 "