summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/client.h15
-rw-r--r--source3/include/ntlmssp.h5
-rw-r--r--source3/include/rpc_dce.h26
-rw-r--r--source3/lib/util.c11
-rw-r--r--source3/libsmb/cliconnect.c6
-rw-r--r--source3/libsmb/clientgen.c42
-rw-r--r--source3/libsmb/ntlmssp.c107
-rw-r--r--source3/libsmb/ntlmssp_parse.c75
-rw-r--r--source3/libsmb/ntlmssp_sign.c206
-rw-r--r--source3/libsmb/pwd_cache.c14
-rw-r--r--source3/libsmb/smbencrypt.c31
-rw-r--r--source3/rpc_client/cli_pipe.c1057
-rw-r--r--source3/rpc_parse/parse_prs.c270
-rw-r--r--source3/rpc_parse/parse_rpc.c26
-rw-r--r--source3/rpc_server/srv_pipe.c40
-rw-r--r--source3/rpcclient/rpcclient.c153
16 files changed, 1272 insertions, 812 deletions
diff --git a/source3/include/client.h b/source3/include/client.h
index d75effd7d0..f3f4ef109a 100644
--- a/source3/include/client.h
+++ b/source3/include/client.h
@@ -131,25 +131,30 @@ struct cli_state {
* Only used in NT domain calls.
*/
+ int pipe_idx; /* Index (into list of known pipes)
+ of the pipe we're talking to,
+ if any */
+
uint16 nt_pipe_fnum; /* Pipe handle. */
+ /* Secure pipe parameters */
+ int pipe_auth_flags;
+
uint16 saved_netlogon_pipe_fnum; /* The "first" pipe to get
the session key for the
schannel. */
struct netsec_auth_struct auth_info;
+ NTLMSSP_CLIENT_STATE *ntlmssp_pipe_state;
+
unsigned char sess_key[16]; /* Current session key. */
- unsigned char ntlmssp_hash[258]; /* ntlmssp data. */
- uint32 ntlmssp_cli_flgs; /* ntlmssp client flags */
- uint32 ntlmssp_srv_flgs; /* ntlmssp server flags */
- uint32 ntlmssp_seq_num; /* ntlmssp sequence number */
DOM_CRED clnt_cred; /* Client credential. */
fstring mach_acct; /* MYNAME$. */
fstring srv_name_slash; /* \\remote server. */
fstring clnt_name_slash; /* \\local client. */
uint16 max_xmit_frag;
uint16 max_recv_frag;
- uint32 ntlmssp_flags;
+
BOOL use_kerberos;
BOOL use_spnego;
diff --git a/source3/include/ntlmssp.h b/source3/include/ntlmssp.h
index 067b2a5880..562e4853cc 100644
--- a/source3/include/ntlmssp.h
+++ b/source3/include/ntlmssp.h
@@ -129,5 +129,10 @@ typedef struct ntlmssp_client_state
/* ntlmv1 */
unsigned char ntlmssp_hash[258];
+ /* it turns out that we don't always get the
+ response in at the time we want to process it.
+ Store it here, until we need it */
+ DATA_BLOB stored_response;
+
} NTLMSSP_CLIENT_STATE;
diff --git a/source3/include/rpc_dce.h b/source3/include/rpc_dce.h
index b99639d68d..dc82f45368 100644
--- a/source3/include/rpc_dce.h
+++ b/source3/include/rpc_dce.h
@@ -51,17 +51,32 @@ enum RPC_PKT_TYPE
/* NTLMSSP signature version */
#define NTLMSSP_SIGN_VERSION 0x01
-/* NTLMSSP auth type and level. */
+/* NTLMSSP auth type */
#define NTLMSSP_AUTH_TYPE 0xa
-#define NTLMSSP_AUTH_LEVEL 0x6
+
+/* DCE-RPC standard identifiers to indicate
+ signing or sealing of an RPC pipe */
+#define RPC_PIPE_AUTH_SIGN_LEVEL 0x5
+#define RPC_PIPE_AUTH_SEAL_LEVEL 0x6
/* Netlogon schannel auth type and level */
#define NETSEC_AUTH_TYPE 0x44
-#define NETSEC_AUTH_LEVEL 0x6
#define NETSEC_SIGNATURE { 0x77, 0x00, 0x7a, 0x00, 0xff, 0xff, 0x00, 0x00 }
#define RPC_AUTH_NETSEC_CHK_LEN 0x20
#define NETLOGON_NEG_SCHANNEL 0x40000000
+enum netsec_direction
+{
+ SENDER_IS_INITIATOR,
+ SENDER_IS_ACCEPTOR
+};
+
+/* Internal Flags to indicate what type of authentication on the pipe */
+#define AUTH_PIPE_SIGN 0x0001
+#define AUTH_PIPE_SEAL 0x0002
+#define AUTH_PIPE_NTLMSSP 0x0004
+#define AUTH_PIPE_NETSEC 0x0008
+
/* Maximum PDU fragment size. */
#define MAX_PDU_FRAG_LEN 0x1630
/* #define MAX_PDU_FRAG_LEN 0x10b8 this is what w2k sets */
@@ -222,8 +237,8 @@ typedef struct rpc_auth_netsec_neg_info
typedef struct rpc_auth_netsec_chk_info
{
uint8 sig [8]; /* 77 00 7a 00 ff ff 00 00 */
- uint8 data1[8];
- uint8 data3[8]; /* verifier, seq num */
+ uint8 packet_digest[8]; /* checksum over the packet, MD5'ed with session key */
+ uint8 seq_num[8]; /* verifier, seq num */
uint8 data8[8]; /* random 8-byte nonce */
} RPC_AUTH_NETSEC_CHK;
@@ -350,5 +365,4 @@ typedef struct rpc_auth_ntlmssp_chk_info
#define RPC_AUTH_NTLMSSP_CHK_LEN 16
-
#endif /* _DCE_RPC_H */
diff --git a/source3/lib/util.c b/source3/lib/util.c
index 6af82f24e5..a7c939fe5a 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -1911,6 +1911,17 @@ void dump_data(int level, const char *buf1,int len)
}
}
+void dump_data_pw(const char *msg, const uchar * data, size_t len)
+{
+#ifdef DEBUG_PASSWORD
+ DEBUG(11, ("%s", msg));
+ if (data != NULL && len > 0)
+ {
+ dump_data(11, data, len);
+ }
+#endif
+}
+
char *tab_depth(int depth)
{
static pstring spaces;
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 18125e26c3..cdd80b7f0c 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -540,6 +540,12 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
ntlmssp_state->use_ntlmv2 = lp_client_ntlmv2_auth();
+ if (cli->sign_info.negotiated_smb_signing
+ || cli->sign_info.mandetory_signing) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+ }
+
do {
nt_status = ntlmssp_client_update(ntlmssp_state,
blob_in, &blob_out);
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index 8d4e8a266c..93fa94c1db 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -203,12 +203,9 @@ void cli_init_creds(struct cli_state *cli, const struct ntuser_creds *usr)
fstrcpy(cli->domain , usr->domain);
fstrcpy(cli->user_name, usr->user_name);
memcpy(&cli->pwd, &usr->pwd, sizeof(usr->pwd));
- cli->ntlmssp_flags = usr->ntlmssp_flags;
- cli->ntlmssp_cli_flgs = usr != NULL ? usr->ntlmssp_flags : 0;
- DEBUG(10,("cli_init_creds: user %s domain %s flgs: %x\nntlmssp_cli_flgs:%x\n",
- cli->user_name, cli->domain,
- cli->ntlmssp_flags,cli->ntlmssp_cli_flgs));
+ DEBUG(10,("cli_init_creds: user %s domain %s\n",
+ cli->user_name, cli->domain));
}
/****************************************************************************
@@ -287,6 +284,8 @@ struct cli_state *cli_initialise(struct cli_state *cli)
cli->initialised = 1;
cli->allocated = alloced_cli;
+ cli->pipe_idx = -1;
+
return cli;
/* Clean up after malloc() error */
@@ -303,17 +302,50 @@ struct cli_state *cli_initialise(struct cli_state *cli)
}
/****************************************************************************
+close the session
+****************************************************************************/
+
+void cli_nt_session_close(struct cli_state *cli)
+{
+ if (cli->ntlmssp_pipe_state) {
+ ntlmssp_client_end(&cli->ntlmssp_pipe_state);
+ }
+
+ cli_close(cli, cli->nt_pipe_fnum);
+ cli->nt_pipe_fnum = 0;
+ cli->pipe_idx = -1;
+}
+
+/****************************************************************************
+close the NETLOGON session holding the session key for NETSEC
+****************************************************************************/
+
+void cli_nt_netlogon_netsec_session_close(struct cli_state *cli)
+{
+ if (cli->saved_netlogon_pipe_fnum != 0) {
+ cli_close(cli, cli->saved_netlogon_pipe_fnum);
+ cli->saved_netlogon_pipe_fnum = 0;
+ }
+}
+
+/****************************************************************************
Close a client connection and free the memory without destroying cli itself.
****************************************************************************/
void cli_close_connection(struct cli_state *cli)
{
+ cli_nt_session_close(cli);
+ cli_nt_netlogon_netsec_session_close(cli);
+
SAFE_FREE(cli->outbuf);
SAFE_FREE(cli->inbuf);
cli_free_signing_context(cli);
data_blob_free(&cli->secblob);
+ if (cli->ntlmssp_pipe_state)
+ ntlmssp_client_end(&cli->ntlmssp_pipe_state);
+
if (cli->mem_ctx) {
talloc_destroy(cli->mem_ctx);
cli->mem_ctx = NULL;
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
index 4dc9d42659..66dc6e08eb 100644
--- a/source3/libsmb/ntlmssp.c
+++ b/source3/libsmb/ntlmssp.c
@@ -409,6 +409,10 @@ static NTSTATUS ntlmssp_client_initial(struct ntlmssp_client_state *ntlmssp_stat
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
}
+ if (ntlmssp_state->use_ntlmv2) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
/* generate the ntlmssp negotiate packet */
msrpc_gen(next_request, "CddAA",
"NTLMSSP",
@@ -435,7 +439,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
DATA_BLOB server_domain_blob;
DATA_BLOB challenge_blob;
- DATA_BLOB struct_blob;
+ DATA_BLOB struct_blob = data_blob(NULL, 0);
char *server_domain;
const char *chal_parse_string;
const char *auth_gen_string;
@@ -443,28 +447,48 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
DATA_BLOB nt_response = data_blob(NULL, 0);
DATA_BLOB session_key = data_blob(NULL, 0);
uint8 datagram_sess_key[16];
+ size_t datagram_sess_key_len;
+#if 0 /* until we know what flag to tigger it on */
generate_random_buffer(datagram_sess_key, sizeof(datagram_sess_key), False);
+ datagram_sess_key_len = sizeof(datagram_sess_key);
+#else
+ ZERO_STRUCT(datagram_sess_key);
+ datagram_sess_key_len = 0;
+#endif
if (!msrpc_parse(&reply, "CdBd",
"NTLMSSP",
&ntlmssp_command,
&server_domain_blob,
&chal_flags)) {
- DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+ DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
+ dump_data(2, reply.data, reply.length);
+
return NT_STATUS_INVALID_PARAMETER;
}
data_blob_free(&server_domain_blob);
+ DEBUG(3, ("Got challenge flags:\n"));
+ debug_ntlmssp_flags(chal_flags);
+
if (chal_flags & NTLMSSP_NEGOTIATE_UNICODE) {
- chal_parse_string = "CdUdbddB";
+ if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+ chal_parse_string = "CdUdbddB";
+ } else {
+ chal_parse_string = "CdUdbdd";
+ }
auth_gen_string = "CdBBUUUBd";
ntlmssp_state->unicode = True;
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
} else if (chal_flags & NTLMSSP_NEGOTIATE_OEM) {
- chal_parse_string = "CdAdbddB";
+ if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+ chal_parse_string = "CdAdbddB";
+ } else {
+ chal_parse_string = "CdAdbdd";
+ }
auth_gen_string = "CdBBAAABd";
ntlmssp_state->unicode = False;
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
@@ -473,6 +497,25 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
return NT_STATUS_INVALID_PARAMETER;
}
+ if (chal_flags & NTLMSSP_NEGOTIATE_LM_KEY && lp_client_lanman_auth()) {
+ /* server forcing us to use LM */
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+ ntlmssp_state->use_ntlmv2 = False;
+ } else {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+ }
+
+ if (!(chal_flags & NTLMSSP_NEGOTIATE_NTLM2)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
+ if (!(chal_flags & NTLMSSP_NEGOTIATE_128)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
+ }
+
+ DEBUG(3, ("NTLMSSP: Set final flags:\n"));
+ debug_ntlmssp_flags(ntlmssp_state->neg_flags);
+
if (!msrpc_parse(&reply, chal_parse_string,
"NTLMSSP",
&ntlmssp_command,
@@ -481,7 +524,8 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
&challenge_blob, 8,
&unkn1, &unkn2,
&struct_blob)) {
- DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+ DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
+ dump_data(2, reply.data, reply.length);
return NT_STATUS_INVALID_PARAMETER;
}
@@ -493,6 +537,11 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
if (ntlmssp_state->use_ntlmv2) {
+ if (!struct_blob.length) {
+ /* be lazy, match win2k - we can't do NTLMv2 without it */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
/* TODO: if the remote server is standalone, then we should replace 'domain'
with the server name as supplied above */
@@ -506,10 +555,12 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
return NT_STATUS_NO_MEMORY;
}
} else {
+ uchar lm_hash[16];
uchar nt_hash[16];
+ E_deshash(ntlmssp_state->password, lm_hash);
E_md4hash(ntlmssp_state->password, nt_hash);
- /* non encrypted password supplied. Ignore ntpass. */
+ /* lanman auth is insecure, it may be disabled */
if (lp_client_lanman_auth()) {
lm_response = data_blob(NULL, 24);
SMBencrypt(ntlmssp_state->password,challenge_blob.data,
@@ -519,8 +570,15 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
nt_response = data_blob(NULL, 24);
SMBNTencrypt(ntlmssp_state->password,challenge_blob.data,
nt_response.data);
+
session_key = data_blob(NULL, 16);
- SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+ if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
+ && lp_client_lanman_auth()) {
+ SMBsesskeygen_lmv1(lm_hash, lm_response.data,
+ session_key.data);
+ } else {
+ SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+ }
}
data_blob_free(&struct_blob);
@@ -533,7 +591,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
ntlmssp_state->domain,
ntlmssp_state->user,
ntlmssp_state->get_global_myname(),
- datagram_sess_key, 16,
+ datagram_sess_key, datagram_sess_key_len,
ntlmssp_state->neg_flags)) {
data_blob_free(&lm_response);
@@ -575,6 +633,8 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_CLIENT_STATE **ntlmssp_state)
(*ntlmssp_state)->unicode = True;
+ (*ntlmssp_state)->use_ntlmv2 = lp_client_ntlmv2_auth();
+
(*ntlmssp_state)->neg_flags =
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_NTLM |
@@ -596,6 +656,7 @@ NTSTATUS ntlmssp_client_end(NTLMSSP_CLIENT_STATE **ntlmssp_state)
data_blob_free(&(*ntlmssp_state)->lm_resp);
data_blob_free(&(*ntlmssp_state)->nt_resp);
data_blob_free(&(*ntlmssp_state)->session_key);
+ data_blob_free(&(*ntlmssp_state)->stored_response);
talloc_destroy(mem_ctx);
}
@@ -606,12 +667,18 @@ NTSTATUS ntlmssp_client_end(NTLMSSP_CLIENT_STATE **ntlmssp_state)
NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state,
DATA_BLOB reply, DATA_BLOB *next_request)
{
+ NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
uint32 ntlmssp_command;
*next_request = data_blob(NULL, 0);
if (!reply.length) {
- return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
- }
+ /* If there is a cached reply, use it - otherwise this is the first packet */
+ if (!ntlmssp_state->stored_response.length) {
+ return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
+ }
+
+ reply = ntlmssp_state->stored_response;
+ }
if (!msrpc_parse(&reply, "Cd",
"NTLMSSP",
@@ -620,9 +687,12 @@ NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state,
}
if (ntlmssp_command == NTLMSSP_CHALLENGE) {
- return ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
+ nt_status = ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
}
- return NT_STATUS_INVALID_PARAMETER;
+ if (ntlmssp_state->stored_response.length) {
+ data_blob_free(&ntlmssp_state->stored_response);
+ }
+ return nt_status;
}
NTSTATUS ntlmssp_set_username(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *user)
@@ -651,3 +721,16 @@ NTSTATUS ntlmssp_set_domain(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *dom
}
return NT_STATUS_OK;
}
+
+/**
+ * Store a DATA_BLOB containing an NTLMSSP response, for use later.
+ * This 'keeps' the data blob - the caller must *not* free it.
+ */
+
+NTSTATUS ntlmssp_client_store_response(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ DATA_BLOB response)
+{
+ data_blob_free(&ntlmssp_state->stored_response);
+ ntlmssp_state->stored_response = response;
+ return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/ntlmssp_parse.c b/source3/libsmb/ntlmssp_parse.c
index ac779a3906..f53afcdcd0 100644
--- a/source3/libsmb/ntlmssp_parse.c
+++ b/source3/libsmb/ntlmssp_parse.c
@@ -220,23 +220,27 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
- if (len1 & 1) {
- /* if odd length and unicode */
- return False;
- }
-
ps = va_arg(ap, char **);
- if (0 < len1) {
- pull_string(NULL, p, blob->data + ptr, sizeof(p),
- len1,
- STR_UNICODE|STR_NOALIGN);
- (*ps) = smb_xstrdup(p);
+ if (len1 == 0 && len2 == 0) {
+ *ps = smb_xstrdup("");
} else {
- (*ps) = smb_xstrdup("");
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+ if (len1 & 1) {
+ /* if odd length and unicode */
+ return False;
+ }
+
+ if (0 < len1) {
+ pull_string(NULL, p, blob->data + ptr, sizeof(p),
+ len1,
+ STR_UNICODE|STR_NOALIGN);
+ (*ps) = smb_xstrdup(p);
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
}
break;
case 'A':
@@ -245,19 +249,23 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
-
ps = va_arg(ap, char **);
- if (0 < len1) {
- pull_string(NULL, p, blob->data + ptr, sizeof(p),
- len1,
- STR_ASCII|STR_NOALIGN);
- (*ps) = smb_xstrdup(p);
+ /* make sure its in the right format - be strict */
+ if (len1 == 0 && len2 == 0) {
+ *ps = smb_xstrdup("");
} else {
- (*ps) = smb_xstrdup("");
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+
+ if (0 < len1) {
+ pull_string(NULL, p, blob->data + ptr, sizeof(p),
+ len1,
+ STR_ASCII|STR_NOALIGN);
+ (*ps) = smb_xstrdup(p);
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
}
break;
case 'B':
@@ -265,12 +273,17 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
+
b = (DATA_BLOB *)va_arg(ap, void *);
- *b = data_blob(blob->data + ptr, len1);
+ if (len1 == 0 && len2 == 0) {
+ *b = data_blob(NULL, 0);
+ } else {
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+ *b = data_blob(blob->data + ptr, len1);
+ }
break;
case 'b':
b = (DATA_BLOB *)va_arg(ap, void *);
diff --git a/source3/libsmb/ntlmssp_sign.c b/source3/libsmb/ntlmssp_sign.c
index 86faf1f5e6..748c008963 100644
--- a/source3/libsmb/ntlmssp_sign.c
+++ b/source3/libsmb/ntlmssp_sign.c
@@ -79,13 +79,18 @@ static void calc_hash(unsigned char *hash, const char *k2, int k2l)
}
static void calc_ntlmv2_hash(unsigned char hash[16], char digest[16],
- const char encrypted_response[16],
+ DATA_BLOB session_key,
const char *constant)
{
struct MD5Context ctx3;
+ /* NOTE: This code is currently complate fantasy - it's
+ got more in common with reality than the previous code
+ (the LM session key is not the right thing to use) but
+ it still needs work */
+
MD5Init(&ctx3);
- MD5Update(&ctx3, encrypted_response, 5);
+ MD5Update(&ctx3, session_key.data, session_key.length);
MD5Update(&ctx3, constant, strlen(constant));
MD5Final(digest, &ctx3);
@@ -113,25 +118,28 @@ static NTSTATUS ntlmssp_make_packet_signiture(NTLMSSP_CLIENT_STATE *ntlmssp_stat
hmac_md5_update(data, length, &ctx);
hmac_md5_final(digest, &ctx);
- if (!msrpc_gen(sig, "Bd", digest, sizeof(digest), ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+ , ntlmssp_state->ntlmssp_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
switch (direction) {
case NTLMSSP_SEND:
- NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data, sig->length);
+ NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data+4, sig->length-4);
break;
case NTLMSSP_RECEIVE:
- NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash, sig->data, sig->length);
+ NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash, sig->data+4, sig->length-4);
break;
}
} else {
uint32 crc;
crc = crc32_calc_buffer(data, length);
- if (!msrpc_gen(sig, "ddd", 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
- NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data, sig->length);
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
}
return NT_STATUS_OK;
}
@@ -140,8 +148,11 @@ NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
const uchar *data, size_t length,
DATA_BLOB *sig)
{
+ NTSTATUS nt_status = ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+
+ /* increment counter on send */
ntlmssp_state->ntlmssp_seq_num++;
- return ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+ return nt_status;
}
/**
@@ -151,8 +162,8 @@ NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
*/
NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
- const uchar *data, size_t length,
- const DATA_BLOB *sig)
+ const uchar *data, size_t length,
+ const DATA_BLOB *sig)
{
DATA_BLOB local_sig;
NTSTATUS nt_status;
@@ -170,9 +181,7 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
return nt_status;
}
- if (memcmp(sig->data, local_sig.data, MIN(sig->length, local_sig.length)) == 0) {
- return NT_STATUS_OK;
- } else {
+ if (memcmp(sig->data+sig->length - 8, local_sig.data+local_sig.length - 8, 8) != 0) {
DEBUG(5, ("BAD SIG: wanted signature of\n"));
dump_data(5, local_sig.data, local_sig.length);
@@ -182,6 +191,97 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
DEBUG(0, ("NTLMSSP packet check failed due to invalid signiture!\n"));
return NT_STATUS_ACCESS_DENIED;
}
+
+ /* increment counter on recieive */
+ ntlmssp_state->ntlmssp_seq_num++;
+
+ return NT_STATUS_OK;
+}
+
+
+/**
+ * Seal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_client_seal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ DEBUG(10,("ntlmssp_client_seal_data: seal\n"));
+ dump_data_pw("ntlmssp clear data\n", data, length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ HMACMD5Context ctx;
+ char seq_num[4];
+ uchar digest[16];
+ SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
+
+ hmac_md5_init_limK_to_64(ntlmssp_state->cli_sign_const, 16, &ctx);
+ hmac_md5_update(seq_num, 4, &ctx);
+ hmac_md5_update(data, length, &ctx);
+ hmac_md5_final(digest, &ctx);
+
+ if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+ , ntlmssp_state->ntlmssp_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dump_data_pw("ntlmssp client sealing hash:\n",
+ ntlmssp_state->cli_seal_hash,
+ sizeof(ntlmssp_state->cli_seal_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->cli_seal_hash, data, length);
+ dump_data_pw("ntlmssp client signing hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data+4, sig->length-4);
+ } else {
+ uint32 crc;
+ crc = crc32_calc_buffer(data, length);
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* The order of these two operations matters - we must first seal the packet,
+ then seal the sequence number - this is becouse the ntlmssp_hash is not
+ constant, but is is rather updated with each iteration */
+
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+ }
+ dump_data_pw("ntlmssp sealed data\n", data, length);
+
+ /* increment counter on send */
+ ntlmssp_state->ntlmssp_seq_num++;
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Unseal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_client_unseal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ DEBUG(10,("ntlmssp_client_unseal_data: seal\n"));
+ dump_data_pw("ntlmssp sealed data\n", data, length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ NTLMSSPcalc_ap(ntlmssp_state->srv_seal_hash, data, length);
+ } else {
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+ }
+ dump_data_pw("ntlmssp clear data\n", data, length);
+
+ return ntlmssp_client_check_packet(ntlmssp_state, data, length, sig);
}
/**
@@ -190,37 +290,69 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
NTSTATUS ntlmssp_client_sign_init(NTLMSSP_CLIENT_STATE *ntlmssp_state)
{
unsigned char p24[24];
- unsigned char lm_hash[16];
+ ZERO_STRUCT(p24);
+
+ DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n"));
+ debug_ntlmssp_flags(ntlmssp_state->neg_flags);
- if (!ntlmssp_state->lm_resp.data) {
- /* can't sign or check signitures yet */
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- E_deshash(ntlmssp_state->password, lm_hash);
-
- NTLMSSPOWFencrypt(lm_hash, ntlmssp_state->lm_resp.data, p24);
-
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
{
- calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash, ntlmssp_state->cli_sign_const, p24, CLI_SIGN);
- calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash, ntlmssp_state->cli_seal_const, p24, CLI_SEAL);
- calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash, ntlmssp_state->srv_sign_const, p24, SRV_SIGN);
- calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash, ntlmssp_state->srv_seal_const, p24, SRV_SEAL);
- }
- else
- {
- char k2[8];
- memcpy(k2, p24, 5);
- k2[5] = 0xe5;
- k2[6] = 0x38;
- k2[7] = 0xb0;
+
+ calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash,
+ ntlmssp_state->cli_sign_const,
+ ntlmssp_state->session_key, CLI_SIGN);
+ dump_data_pw("NTLMSSP client sign hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash,
+ ntlmssp_state->cli_seal_const,
+ ntlmssp_state->session_key, CLI_SEAL);
+ dump_data_pw("NTLMSSP client sesl hash:\n",
+ ntlmssp_state->cli_seal_hash,
+ sizeof(ntlmssp_state->cli_seal_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash,
+ ntlmssp_state->srv_sign_const,
+ ntlmssp_state->session_key, SRV_SIGN);
+ dump_data_pw("NTLMSSP server sign hash:\n",
+ ntlmssp_state->srv_sign_hash,
+ sizeof(ntlmssp_state->srv_sign_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash,
+ ntlmssp_state->srv_seal_const,
+ ntlmssp_state->session_key, SRV_SEAL);
+ dump_data_pw("NTLMSSP server seal hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+ }
+ else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
+ if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 8) {
+ /* can't sign or check signitures yet */
+ DEBUG(5, ("NTLMSSP Sign/Seal - cannot use LM KEY yet\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(5, ("NTLMSSP Sign/Seal - using LM KEY\n"));
+
+ calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 8);
+ dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ } else {
+ if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 16) {
+ /* can't sign or check signitures yet */
+ DEBUG(5, ("NTLMSSP Sign/Seal - cannot use NT KEY yet\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
- calc_hash(ntlmssp_state->ntlmssp_hash, k2, 8);
+ DEBUG(5, ("NTLMSSP Sign/Seal - using NT KEY\n"));
+
+ calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 16);
+ dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
}
ntlmssp_state->ntlmssp_seq_num = 0;
- ZERO_STRUCT(lm_hash);
return NT_STATUS_OK;
}
diff --git a/source3/libsmb/pwd_cache.c b/source3/libsmb/pwd_cache.c
index 7ddcf853c4..f45832d7d7 100644
--- a/source3/libsmb/pwd_cache.c
+++ b/source3/libsmb/pwd_cache.c
@@ -43,15 +43,10 @@ static void pwd_init(struct pwd_info *pwd)
static void pwd_make_lm_nt_16(struct pwd_info *pwd, const char *clr)
{
- pstring dos_passwd;
-
pwd_init(pwd);
- push_ascii_pstring(dos_passwd, clr);
-
- nt_lm_owf_gen(dos_passwd, pwd->smb_nt_pwd, pwd->smb_lm_pwd);
+ nt_lm_owf_gen(clr, pwd->smb_nt_pwd, pwd->smb_lm_pwd);
pwd->null_pwd = False;
- pwd->cleartext = False;
pwd->crypted = False;
}
@@ -61,12 +56,9 @@ static void pwd_make_lm_nt_16(struct pwd_info *pwd, const char *clr)
void pwd_set_cleartext(struct pwd_info *pwd, const char *clr)
{
- pwd_init(pwd);
- push_ascii_fstring(pwd->password, clr);
- pwd->cleartext = True;
- pwd->null_pwd = False;
- pwd->crypted = False;
pwd_make_lm_nt_16(pwd, clr);
+ fstrcpy(pwd->password, clr);
+ pwd->cleartext = True;
}
/****************************************************************************
diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c
index c1b3880299..7a1a2d7d18 100644
--- a/source3/libsmb/smbencrypt.c
+++ b/source3/libsmb/smbencrypt.c
@@ -271,6 +271,8 @@ void SMBOWFencrypt_ntv2(const uchar kr[16],
void SMBsesskeygen_ntv2(const uchar kr[16],
const uchar * nt_resp, uint8 sess_key[16])
{
+ /* a very nice, 128 bit, variable session key */
+
HMACMD5Context ctx;
hmac_md5_init_limK_to_64(kr, 16, &ctx);
@@ -286,6 +288,9 @@ void SMBsesskeygen_ntv2(const uchar kr[16],
void SMBsesskeygen_ntv1(const uchar kr[16],
const uchar * nt_resp, uint8 sess_key[16])
{
+ /* yes, this session key does not change - yes, this
+ is a problem - but it is 128 bits */
+
mdfour((unsigned char *)sess_key, kr, 16);
#ifdef DEBUG_PASSWORD
@@ -294,6 +299,32 @@ void SMBsesskeygen_ntv1(const uchar kr[16],
#endif
}
+void SMBsesskeygen_lmv1(const uchar lm_hash[16],
+ const uchar lm_resp[24], /* only uses 8 */
+ uint8 sess_key[16])
+{
+ /* Calculate the LM session key (effective length 40 bits,
+ but changes with each session) */
+
+ uchar p24[24];
+ uchar partial_lm_hash[16];
+
+ memcpy(partial_lm_hash, lm_hash, 8);
+ memset(partial_lm_hash + 8, 0xbd, 8);
+
+ SMBOWFencrypt(lm_hash, lm_resp, p24);
+
+ memcpy(sess_key, p24, 16);
+ sess_key[5] = 0xe5;
+ sess_key[6] = 0x38;
+ sess_key[7] = 0xb0;
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_lmv1:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
DATA_BLOB NTLMv2_generate_names_blob(const char *hostname,
const char *domain)
{
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index 5fb0205bfa..5ac7aaa441 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -28,6 +28,23 @@
extern struct pipe_id_info pipe_names[];
+void get_auth_type_level(int pipe_auth_flags, int *auth_type, int *auth_level)
+{
+ *auth_type = 0;
+ *auth_level = 0;
+ if (pipe_auth_flags & AUTH_PIPE_SEAL) {
+ *auth_level = RPC_PIPE_AUTH_SEAL_LEVEL;
+ } else if (pipe_auth_flags & AUTH_PIPE_SIGN) {
+ *auth_level = RPC_PIPE_AUTH_SIGN_LEVEL;
+ }
+
+ if (pipe_auth_flags & AUTH_PIPE_NETSEC) {
+ *auth_type = NETSEC_AUTH_TYPE;
+ } else if (pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+ *auth_type = NTLMSSP_AUTH_TYPE;
+ }
+}
+
/********************************************************************
Rpc pipe call id.
********************************************************************/
@@ -132,32 +149,6 @@ static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr,
return (rhdr->pkt_type != RPC_FAULT);
}
-static void NTLMSSPcalc_ap( struct cli_state *cli, unsigned char *data, uint32 len)
-{
- unsigned char *hash = cli->ntlmssp_hash;
- unsigned char index_i = hash[256];
- unsigned char index_j = hash[257];
- int ind;
-
- for( ind = 0; ind < len; ind++) {
- unsigned char tc;
- unsigned char t;
-
- index_i++;
- index_j += hash[index_i];
-
- tc = hash[index_i];
- hash[index_i] = hash[index_j];
- hash[index_j] = tc;
-
- t = hash[index_i] + hash[index_j];
- data[ind] = data[ind] ^ hash[t];
- }
-
- hash[256] = index_i;
- hash[257] = index_j;
-}
-
/****************************************************************************
Verify data on an rpc pipe.
The VERIFY & SEAL code is only executed on packets that look like this :
@@ -175,8 +166,10 @@ static void NTLMSSPcalc_ap( struct cli_state *cli, unsigned char *data, uint32 l
****************************************************************************/
static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
- uint32 fragment_start, int len, int auth_len, int *pauth_padding_len)
+ uint32 fragment_start, int len, int auth_len, uint8 pkt_type,
+ int *pauth_padding_len)
{
+
/*
* The following is that length of the data we must sign or seal.
* This doesn't include the RPC headers or the auth_len or the RPC_HDR_AUTH_LEN
@@ -190,190 +183,194 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
*/
char *reply_data = prs_data_p(rdata) + fragment_start + RPC_HEADER_LEN + RPC_HDR_REQ_LEN;
- BOOL auth_verify = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SIGN) != 0);
- BOOL auth_seal = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SEAL) != 0);
- BOOL auth_schannel = (cli->saved_netlogon_pipe_fnum != 0);
+ RPC_HDR_AUTH rhdr_auth;
*pauth_padding_len = 0;
- DEBUG(5,("rpc_auth_pipe: len: %d auth_len: %d verify %s seal %s schannel %s\n",
- len, auth_len, BOOLSTR(auth_verify), BOOLSTR(auth_seal), BOOLSTR(auth_schannel)));
-
- /*
- * Unseal any sealed data in the PDU, not including the
- * 8 byte auth_header or the auth_data.
- */
+ if (auth_len == 0) {
+ if (cli->pipe_auth_flags == 0) {
+ /* move along, nothing to see here */
+ return True;
+ }
- if (auth_seal) {
- DEBUG(10,("rpc_auth_pipe: unseal\n"));
- dump_data(100, reply_data, data_len);
- NTLMSSPcalc_ap(cli, (uchar*)reply_data, data_len);
- dump_data(100, reply_data, data_len);
+ DEBUG(2, ("No authenticaton header recienved on reply, but this pipe is authenticated\n"));
+ return False;
}
- if (auth_verify || auth_seal) {
- RPC_HDR_AUTH rhdr_auth;
- prs_struct auth_req;
- char data[RPC_HDR_AUTH_LEN];
- /*
- * We set dp to be the end of the packet, minus the auth_len
- * and the length of the header that preceeds the auth_data.
- */
- char *dp = prs_data_p(rdata) + len - auth_len - RPC_HDR_AUTH_LEN;
+ DEBUG(5,("rpc_auth_pipe: pkt_type: %d len: %d auth_len: %d NTLMSSP %s schannel %s sign %s seal %s \n",
+ pkt_type, len, auth_len,
+ BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP),
+ BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_NETSEC),
+ BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_SIGN),
+ BOOLSTR(cli->pipe_auth_flags & AUTH_PIPE_SEAL)));
- if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
- DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+ {
+ int auth_type;
+ int auth_level;
+ char *dp = prs_data_p(rdata) + fragment_start + len -
+ RPC_HDR_AUTH_LEN - auth_len;
+ prs_struct auth_verf;
+
+ if (dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+ DEBUG(0,("rpc_auth_pipe: schannel auth data > data size !\n"));
return False;
}
- memcpy(data, dp, sizeof(data));
-
- prs_init(&auth_req , 0, cli->mem_ctx, UNMARSHALL);
+ DEBUG(10,("rpc_auth_pipe: packet:\n"));
+ dump_data(100, dp, auth_len);
- /* The endianness must be preserved... JRA. */
+ prs_init(&auth_verf, RPC_HDR_AUTH_LEN, cli->mem_ctx, UNMARSHALL);
- prs_set_endian_data(&auth_req, rdata->bigendian_data);
+ /* The endinness must be preserved. JRA. */
+ prs_set_endian_data( &auth_verf, rdata->bigendian_data);
- prs_give_memory(&auth_req, data, RPC_HDR_AUTH_LEN, False);
+ prs_copy_data_in(&auth_verf, dp, RPC_HDR_AUTH_LEN);
+ prs_set_offset(&auth_verf, 0);
- /*
- * Unmarshall the 8 byte auth_header that comes before the
- * auth data.
- */
- if(!smb_io_rpc_hdr_auth("hdr_auth", &rhdr_auth, &auth_req, 0)) {
- DEBUG(0,("rpc_auth_pipe: unmarshalling RPC_HDR_AUTH failed.\n"));
+ if (!smb_io_rpc_hdr_auth("auth_hdr", &rhdr_auth, &auth_verf, 0)) {
+ DEBUG(0, ("rpc_auth_pipe: Could not parse auth header\n"));
return False;
}
- if (!rpc_hdr_auth_chk(&rhdr_auth)) {
- DEBUG(0,("rpc_auth_pipe: rpc_hdr_auth_chk failed.\n"));
+ /* Let the caller know how much padding at the end of the data */
+ *pauth_padding_len = rhdr_auth.padding;
+
+ /* Check it's the type of reply we were expecting to decode */
+
+ get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level);
+ if (rhdr_auth.auth_type != auth_type) {
+ DEBUG(0, ("BAD auth type %d (should be %d)\n",
+ rhdr_auth.auth_type, auth_type));
return False;
}
- }
-
- /*
- * Now unseal and check the auth verifier in the auth_data at
- * then end of the packet. The 4 bytes skipped in the unseal
- * seem to be a buffer pointer preceeding the sealed data.
- */
-
- if (auth_verify) {
- RPC_AUTH_NTLMSSP_CHK chk;
- uint32 crc32;
- prs_struct auth_verf;
- char data[RPC_AUTH_NTLMSSP_CHK_LEN];
- char *dp = prs_data_p(rdata) + len - auth_len;
-
- if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
- DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+
+ if (rhdr_auth.auth_level != auth_level) {
+ DEBUG(0, ("BAD auth level %d (should be %d)\n",
+ rhdr_auth.auth_level, auth_level));
return False;
}
+ }
- DEBUG(10,("rpc_auth_pipe: verify\n"));
- dump_data(100, dp, auth_len);
- NTLMSSPcalc_ap(cli, (uchar*)(dp+4), auth_len - 4);
-
- memcpy(data, dp, RPC_AUTH_NTLMSSP_CHK_LEN);
- dump_data(100, data, auth_len);
-
- prs_init(&auth_verf, 0, cli->mem_ctx, UNMARSHALL);
-
- /* The endinness must be preserved. JRA. */
- prs_set_endian_data( &auth_verf, rdata->bigendian_data);
+ if (pkt_type == RPC_BINDACK) {
+ if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+ char *dp = prs_data_p(rdata) + len - auth_len;
+
+ if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+ DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+ return False;
+ }
+
+ /* save the reply away, for use a little later */
+ return (NT_STATUS_IS_OK(ntlmssp_client_store_response(cli->ntlmssp_pipe_state,
+ data_blob(dp, auth_len))));
+ }
+ if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
+ /* nothing to do here - we don't seem to be able to validate the
+ bindack based on VL's comments */
+ return True;
+ }
+ }
+
+ if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+ NTSTATUS nt_status;
+ DATA_BLOB sig;
+ if ((cli->pipe_auth_flags & AUTH_PIPE_SIGN) ||
+ (cli->pipe_auth_flags & AUTH_PIPE_SEAL)) {
+ char *dp = prs_data_p(rdata) + len - auth_len;
+
+ if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+ DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
+ return False;
+ }
+
+ if (auth_len != RPC_AUTH_NTLMSSP_CHK_LEN) {
+ DEBUG(0,("rpc_auth_pipe: wrong ntlmssp auth len %d\n", auth_len));
+ return False;
+ }
+
+ sig = data_blob(dp, auth_len);
+ }
+
+ /*
+ * Unseal any sealed data in the PDU, not including the
+ * 8 byte auth_header or the auth_data.
+ */
- prs_give_memory(&auth_verf, data, RPC_AUTH_NTLMSSP_CHK_LEN, False);
+ /*
+ * Now unseal and check the auth verifier in the auth_data at
+ * the end of the packet.
+ */
- if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk, &auth_verf, 0)) {
- DEBUG(0,("rpc_auth_pipe: unmarshalling RPC_AUTH_NTLMSSP_CHK failed.\n"));
- return False;
+ if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) {
+ if (data_len < 0) {
+ DEBUG(1, ("Can't unseal - data_len < 0!!\n"));
+ return False;
+ }
+ nt_status = ntlmssp_client_unseal_packet(cli->ntlmssp_pipe_state,
+ reply_data, data_len,
+ &sig);
+ }
+ else if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
+ nt_status = ntlmssp_client_check_packet(cli->ntlmssp_pipe_state,
+ reply_data, data_len,
+ &sig);
}
- crc32 = crc32_calc_buffer(reply_data, data_len);
+ data_blob_free(&sig);
- if (!rpc_auth_ntlmssp_chk(&chk, crc32 , cli->ntlmssp_seq_num)) {
- DEBUG(0,("rpc_auth_pipe: rpc_auth_ntlmssp_chk failed.\n"));
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("rpc_auth_pipe: could not validate "
+ "incoming NTLMSSP packet!\n"));
return False;
}
- cli->ntlmssp_seq_num++;
}
- if (auth_schannel) {
+ if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
RPC_AUTH_NETSEC_CHK chk;
- RPC_HDR_AUTH rhdr_auth;
- char data[RPC_HDR_AUTH_LEN+RPC_AUTH_NETSEC_CHK_LEN];
- char *dp = prs_data_p(rdata) + fragment_start + len -
- RPC_HDR_AUTH_LEN - RPC_AUTH_NETSEC_CHK_LEN;
- prs_struct auth_verf;
-
- if (auth_len != RPC_AUTH_NETSEC_CHK_LEN) {
-
- if ( (auth_len == 12) &&
- (cli->auth_info.seq_num == 0) ) {
-
- /* This is the reply to our bind. Ok,
- the sequence number can wrap
- around. But this only means that
- every 4 billion request we
- misdetect a wrong length in a
- reply. This is an error condition
- which will lead to failure anyway
- later.
-
- The reply contains a
- RPC_AUTH_VERIFIER with no content
- (12 bytes), so ignore it.
- */
- return True;
- }
+ prs_struct netsec_verf;
- DEBUG(0,("rpc_auth_pipe: wrong schannel auth len %d\n", auth_len));
+ char *dp = prs_data_p(rdata) + len - auth_len;
+
+ if(dp - prs_data_p(rdata) > prs_data_size(rdata)) {
+ DEBUG(0,("rpc_auth_pipe: auth data > data size !\n"));
return False;
}
- if (dp - prs_data_p(rdata) > prs_data_size(rdata)) {
- DEBUG(0,("rpc_auth_pipe: schannel auth data > data size !\n"));
+ if (auth_len != RPC_AUTH_NETSEC_CHK_LEN) {
+ DEBUG(0,("rpc_auth_pipe: wrong schannel auth len %d\n", auth_len));
return False;
}
- DEBUG(10,("rpc_auth_pipe: schannel verify netsec\n"));
- dump_data(100, dp, auth_len);
-
- memcpy(data, dp, sizeof(data));
- dump_data(100, data, sizeof(data));
-
- prs_init(&auth_verf, 0, cli->mem_ctx, UNMARSHALL);
+ prs_init(&netsec_verf, RPC_AUTH_NETSEC_CHK_LEN,
+ cli->mem_ctx, UNMARSHALL);
/* The endinness must be preserved. JRA. */
- prs_set_endian_data( &auth_verf, rdata->bigendian_data);
-
- prs_give_memory(&auth_verf, data, sizeof(data), False);
-
- if (!smb_io_rpc_hdr_auth("auth_hdr", &rhdr_auth, &auth_verf, 0)) {
- DEBUG(0, ("rpc_auth_pipe: Could not parse schannel auth header\n"));
- return False;
- }
+ prs_set_endian_data( &netsec_verf, rdata->bigendian_data);
- if ((rhdr_auth.auth_type != NETSEC_AUTH_TYPE) ||
- (rhdr_auth.auth_level != NETSEC_AUTH_LEVEL)) {
- DEBUG(0, ("rpc_auth_pipe: Got wrong schannel auth type/level: %d/%d\n",
- rhdr_auth.auth_type, rhdr_auth.auth_level));
- return False;
- }
+ prs_copy_data_in(&netsec_verf, dp, auth_len);
+ prs_set_offset(&netsec_verf, 0);
- if (!smb_io_rpc_auth_netsec_chk("schannel_auth_sign", &chk, &auth_verf, 0)) {
+ if (!smb_io_rpc_auth_netsec_chk("schannel_auth_sign",
+ &chk, &netsec_verf, 0)) {
DEBUG(0, ("rpc_auth_pipe: schannel unmarshalling "
"RPC_AUTH_NETSECK_CHK failed\n"));
+ prs_mem_free(&netsec_verf);
return False;
}
- cli->auth_info.seq_num++;
-
- if (!netsec_decode(&cli->auth_info, &chk, reply_data, data_len)) {
+ if (!netsec_decode(&cli->auth_info,
+ cli->pipe_auth_flags,
+ SENDER_IS_ACCEPTOR,
+ &chk, reply_data, data_len)) {
DEBUG(0, ("rpc_auth_pipe: Could not decode schannel\n"));
+ prs_mem_free(&netsec_verf);
return False;
}
- *pauth_padding_len = rhdr_auth.padding;
+
+ cli->auth_info.seq_num++;
+
+ prs_mem_free(&netsec_verf);
}
return True;
}
@@ -403,7 +400,8 @@ static BOOL rpc_auth_pipe(struct cli_state *cli, prs_struct *rdata,
****************************************************************************/
-static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rdata)
+static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rdata,
+ uint8 expected_pkt_type)
{
uint32 len;
char *rparam = NULL;
@@ -419,6 +417,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rd
uint32 current_offset = 0;
uint32 fragment_start = 0;
uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : 1024;
+ int auth_padding_len = 0;
/* Create setup parameters - must be in native byte order. */
@@ -476,6 +475,12 @@ static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rd
}
}
+ if (rhdr.pkt_type == RPC_BINDNACK) {
+ DEBUG(3, ("Bind NACK received on pipe %x!\n", (int)cli->nt_pipe_fnum));
+ prs_mem_free(rdata);
+ return False;
+ }
+
if (rhdr.pkt_type == RPC_RESPONSE) {
RPC_HDR_RESP rhdr_resp;
if(!smb_io_rpc_hdr_resp("rpc_hdr_resp", &rhdr_resp, rdata, 0)) {
@@ -485,6 +490,12 @@ static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rd
}
}
+ if (rhdr.pkt_type != expected_pkt_type) {
+ DEBUG(3, ("Connection to pipe %x got an unexpected RPC packet type - %d, not %d\n", (int)cli->nt_pipe_fnum, rhdr.pkt_type, expected_pkt_type));
+ prs_mem_free(rdata);
+ return False;
+ }
+
DEBUG(5,("rpc_api_pipe: len left: %u smbtrans read: %u\n",
(unsigned int)len, (unsigned int)rdata_len ));
@@ -507,12 +518,13 @@ static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rd
* Now we have a complete PDU, check the auth struct if any was sent.
*/
- if (rhdr.auth_len != 0) {
- int auth_padding_len = 0;
+ if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len,
+ rhdr.auth_len, rhdr.pkt_type, &auth_padding_len)) {
+ prs_mem_free(rdata);
+ return False;
+ }
- if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len,
- rhdr.auth_len, &auth_padding_len))
- return False;
+ if (rhdr.auth_len != 0) {
/*
* Drop the auth footers from the current offset.
* We need this if there are more fragments.
@@ -543,7 +555,7 @@ static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rd
prs_struct hps;
uint8 eclass;
uint32 ecode;
-
+
/*
* First read the header of the next PDU.
*/
@@ -596,8 +608,10 @@ static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rd
* Now read the rest of the PDU.
*/
- if (!rpc_read(cli, rdata, len, &current_offset))
+ if (!rpc_read(cli, rdata, len, &current_offset)) {
+ prs_mem_free(rdata);
return False;
+ }
fragment_start = current_offset - len - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
@@ -605,12 +619,15 @@ static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rd
* Verify any authentication footer.
*/
+
+ if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len,
+ rhdr.auth_len, rhdr.pkt_type, &auth_padding_len)) {
+ prs_mem_free(rdata);
+ return False;
+ }
+
if (rhdr.auth_len != 0 ) {
- int auth_padding_len = 0;
-
- if(!rpc_auth_pipe(cli, rdata, fragment_start, rhdr.frag_len,
- rhdr.auth_len, &auth_padding_len))
- return False;
+
/*
* Drop the auth footers from the current offset.
* The auth footers consist of the auth_data and the
@@ -633,70 +650,72 @@ static BOOL rpc_api_pipe(struct cli_state *cli, prs_struct *data, prs_struct *rd
********************************************************************/
-static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, BOOL do_netsec, uint32 rpc_call_id,
- RPC_IFACE *abstract, RPC_IFACE *transfer,
- const char *my_name, const char *domain, uint32 neg_flags)
+static NTSTATUS create_rpc_bind_req(struct cli_state *cli, prs_struct *rpc_out,
+ uint32 rpc_call_id,
+ RPC_IFACE *abstract, RPC_IFACE *transfer,
+ const char *my_name, const char *domain)
{
RPC_HDR hdr;
RPC_HDR_RB hdr_rb;
- char buffer[4096];
- prs_struct auth_info;
+ RPC_HDR_AUTH hdr_auth;
int auth_len = 0;
+ int auth_type, auth_level;
+ size_t saved_hdr_offset;
- prs_init(&auth_info, 0, prs_get_mem_context(rpc_out), MARSHALL);
-
- if (do_auth) {
- RPC_HDR_AUTH hdr_auth;
- RPC_AUTH_VERIFIER auth_verifier;
- RPC_AUTH_NTLMSSP_NEG ntlmssp_neg;
+ prs_struct auth_info;
+ prs_init(&auth_info, RPC_HDR_AUTH_LEN, /* we will need at least this much */
+ prs_get_mem_context(rpc_out), MARSHALL);
+ if (cli->pipe_auth_flags) {
+ get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level);
+
/*
* Create the auth structs we will marshall.
*/
-
- init_rpc_hdr_auth(&hdr_auth, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, 0x00, 1);
- init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_NEGOTIATE);
- init_rpc_auth_ntlmssp_neg(&ntlmssp_neg, neg_flags, my_name, domain);
-
- /*
- * Use the 4k buffer to store the auth info.
- */
-
- prs_give_memory( &auth_info, buffer, sizeof(buffer), False);
-
+
+ init_rpc_hdr_auth(&hdr_auth, auth_type, auth_level, 0x00, 1);
+
/*
* Now marshall the data into the temporary parse_struct.
*/
-
+
if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &auth_info, 0)) {
DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_AUTH.\n"));
- return False;
+ prs_mem_free(&auth_info);
+ return NT_STATUS_NO_MEMORY;
}
+ saved_hdr_offset = prs_offset(&auth_info);
+ }
+
+ if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
- if(!smb_io_rpc_auth_verifier("auth_verifier", &auth_verifier, &auth_info, 0)) {
- DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_AUTH_VERIFIER.\n"));
- return False;
- }
+ NTSTATUS nt_status;
+ DATA_BLOB null_blob = data_blob(NULL, 0);
+ DATA_BLOB request;
- if(!smb_io_rpc_auth_ntlmssp_neg("ntlmssp_neg", &ntlmssp_neg, &auth_info, 0)) {
- DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_AUTH_NTLMSSP_NEG.\n"));
- return False;
+ DEBUG(5, ("Processing NTLMSSP Negotiate\n"));
+ nt_status = ntlmssp_client_update(cli->ntlmssp_pipe_state,
+ null_blob,
+ &request);
+
+ if (!NT_STATUS_EQUAL(nt_status,
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ prs_mem_free(&auth_info);
+ return nt_status;
}
/* Auth len in the rpc header doesn't include auth_header. */
- auth_len = prs_offset(&auth_info) - RPC_HDR_AUTH_LEN;
- }
+ auth_len = request.length;
+ prs_copy_data_in(&auth_info, request.data, request.length);
- if (do_netsec) {
- RPC_HDR_AUTH hdr_auth;
- RPC_AUTH_NETSEC_NEG netsec_neg;
+ DEBUG(5, ("NTLMSSP Negotiate:\n"));
+ dump_data(5, request.data, request.length);
- /*
- * Create the auth structs we will marshall.
- */
+ data_blob_free(&request);
- init_rpc_hdr_auth(&hdr_auth, NETSEC_AUTH_TYPE, NETSEC_AUTH_LEVEL,
- 0x00, 1);
+ }
+ else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
+ RPC_AUTH_NETSEC_NEG netsec_neg;
/* Use lp_workgroup() if domain not specified */
@@ -706,30 +725,19 @@ static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, BOOL do_netse
init_rpc_auth_netsec_neg(&netsec_neg, domain, my_name);
/*
- * Use the 4k buffer to store the auth info.
- */
-
- prs_give_memory( &auth_info, buffer, sizeof(buffer), False);
-
- /*
* Now marshall the data into the temporary parse_struct.
*/
- if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth, &auth_info, 0)) {
- DEBUG(0,("Failed to marshall RPC_HDR_AUTH.\n"));
- return False;
- }
-
if(!smb_io_rpc_auth_netsec_neg("netsec_neg",
&netsec_neg, &auth_info, 0)) {
DEBUG(0,("Failed to marshall RPC_AUTH_NETSEC_NEG.\n"));
- return False;
+ prs_mem_free(&auth_info);
+ return NT_STATUS_NO_MEMORY;
}
/* Auth len in the rpc header doesn't include auth_header. */
- auth_len = prs_offset(&auth_info) - RPC_HDR_AUTH_LEN;
+ auth_len = prs_offset(&auth_info) - saved_hdr_offset;
}
-
/* create the request RPC_HDR */
init_rpc_hdr(&hdr, RPC_BIND, 0x3, rpc_call_id,
RPC_HEADER_LEN + RPC_HDR_RB_LEN + prs_offset(&auth_info),
@@ -737,7 +745,8 @@ static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, BOOL do_netse
if(!smb_io_rpc_hdr("hdr" , &hdr, rpc_out, 0)) {
DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR.\n"));
- return False;
+ prs_mem_free(&auth_info);
+ return NT_STATUS_NO_MEMORY;
}
/* create the bind request RPC_HDR_RB */
@@ -747,21 +756,22 @@ static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, BOOL do_netse
/* Marshall the bind request data */
if(!smb_io_rpc_hdr_rb("", &hdr_rb, rpc_out, 0)) {
DEBUG(0,("create_rpc_bind_req: failed to marshall RPC_HDR_RB.\n"));
- return False;
+ prs_mem_free(&auth_info);
+ return NT_STATUS_NO_MEMORY;
}
/*
* Grow the outgoing buffer to store any auth info.
*/
- if(hdr.auth_len != 0) {
+ if(auth_len != 0) {
if(!prs_append_prs_data( rpc_out, &auth_info)) {
DEBUG(0,("create_rpc_bind_req: failed to grow parse struct to add auth.\n"));
- return False;
+ prs_mem_free(&auth_info);
+ return NT_STATUS_NO_MEMORY;
}
}
-
- return True;
+ return NT_STATUS_OK;
}
/*******************************************************************
@@ -771,90 +781,71 @@ static BOOL create_rpc_bind_req(prs_struct *rpc_out, BOOL do_auth, BOOL do_netse
the authentication handshake.
********************************************************************/
-static BOOL create_rpc_bind_resp(struct pwd_info *pwd,
- const char *domain, const char *user_name, const char *my_name,
- uint32 ntlmssp_cli_flgs,
- uint32 rpc_call_id,
- prs_struct *rpc_out)
+static NTSTATUS create_rpc_bind_resp(struct cli_state *cli,
+ uint32 rpc_call_id,
+ prs_struct *rpc_out)
{
- unsigned char lm_owf[24];
- unsigned char nt_owf[24];
+ NTSTATUS nt_status;
RPC_HDR hdr;
RPC_HDR_AUTHA hdr_autha;
- RPC_AUTH_VERIFIER auth_verifier;
- RPC_AUTH_NTLMSSP_RESP ntlmssp_resp;
- char buffer[4096];
- prs_struct auth_info;
-
- /*
- * Marshall the variable length data into a temporary parse
- * struct, pointing into a 4k local buffer.
- */
- prs_init(&auth_info, 0, prs_get_mem_context(rpc_out), MARSHALL);
-
- /*
- * Use the 4k buffer to store the auth info.
- */
-
- prs_give_memory( &auth_info, buffer, sizeof(buffer), False);
-
- /*
- * Create the variable length auth_data.
- */
-
- init_rpc_auth_verifier(&auth_verifier, "NTLMSSP", NTLMSSP_AUTH);
-
- pwd_get_lm_nt_owf(pwd, lm_owf, nt_owf);
-
- init_rpc_auth_ntlmssp_resp(&ntlmssp_resp,
- lm_owf, nt_owf,
- domain, user_name, my_name,
- ntlmssp_cli_flgs);
-
- /*
- * Marshall the variable length auth_data into a temp parse_struct.
- */
-
- if(!smb_io_rpc_auth_verifier("auth_verifier", &auth_verifier, &auth_info, 0)) {
- DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_AUTH_VERIFIER.\n"));
- return False;
- }
-
- if(!smb_io_rpc_auth_ntlmssp_resp("ntlmssp_resp", &ntlmssp_resp, &auth_info, 0)) {
- DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_AUTH_NTLMSSP_RESP.\n"));
- return False;
+ DATA_BLOB ntlmssp_null_response = data_blob(NULL, 0);
+ DATA_BLOB ntlmssp_reply;
+ int auth_type, auth_level;
+
+ /* The response is picked up from the internal cache,
+ where it was placed by the rpc_auth_pipe() code */
+ nt_status = ntlmssp_client_update(cli->ntlmssp_pipe_state,
+ ntlmssp_null_response,
+ &ntlmssp_reply);
+
+ if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ return nt_status;
}
/* Create the request RPC_HDR */
init_rpc_hdr(&hdr, RPC_BINDRESP, 0x0, rpc_call_id,
- RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN + prs_offset(&auth_info),
- prs_offset(&auth_info) );
-
+ RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN + ntlmssp_reply.length,
+ ntlmssp_reply.length );
+
/* Marshall it. */
if(!smb_io_rpc_hdr("hdr", &hdr, rpc_out, 0)) {
DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_HDR.\n"));
- return False;
+ data_blob_free(&ntlmssp_reply);
+ return NT_STATUS_NO_MEMORY;
}
+ get_auth_type_level(cli->pipe_auth_flags, &auth_type, &auth_level);
+
/* Create the request RPC_HDR_AUTHA */
init_rpc_hdr_autha(&hdr_autha, MAX_PDU_FRAG_LEN, MAX_PDU_FRAG_LEN,
- NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, 0x00);
+ auth_type, auth_level, 0x00);
if(!smb_io_rpc_hdr_autha("hdr_autha", &hdr_autha, rpc_out, 0)) {
DEBUG(0,("create_rpc_bind_resp: failed to marshall RPC_HDR_AUTHA.\n"));
- return False;
+ data_blob_free(&ntlmssp_reply);
+ return NT_STATUS_NO_MEMORY;
}
/*
* Append the auth data to the outgoing buffer.
*/
- if(!prs_append_prs_data(rpc_out, &auth_info)) {
+ if(!prs_copy_data_in(rpc_out, ntlmssp_reply.data, ntlmssp_reply.length)) {
DEBUG(0,("create_rpc_bind_req: failed to grow parse struct to add auth.\n"));
- return False;
+ data_blob_free(&ntlmssp_reply);
+ return NT_STATUS_NO_MEMORY;
}
- return True;
+ if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
+ nt_status = ntlmssp_client_sign_init(cli->ntlmssp_pipe_state);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+ }
+
+ data_blob_free(&ntlmssp_reply);
+ return NT_STATUS_OK;
}
@@ -905,34 +896,17 @@ static uint32 create_rpc_request(prs_struct *rpc_out, uint8 op_num, int data_len
}
/*******************************************************************
- Puts an NTLMSSP auth header into an rpc request.
- ********************************************************************/
-
-static BOOL create_ntlmssp_auth_hdr(prs_struct *outgoing_packet, BOOL auth_verify)
-{
- RPC_HDR_AUTH hdr_auth;
-
- init_rpc_hdr_auth(&hdr_auth, NTLMSSP_AUTH_TYPE,
- NTLMSSP_AUTH_LEVEL, 0x08,
- (auth_verify ? 1 : 0));
- if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth,
- outgoing_packet, 0)) {
- DEBUG(0,("create_auth_hdr:Failed to marshal RPC_HDR_AUTH.\n"));
- return False;
- }
- return True;
-}
-
-/*******************************************************************
- Puts a NETLOGON schannel auth header into an rpc request.
+ Puts an auth header into an rpc request.
********************************************************************/
-static BOOL create_netsec_auth_hdr(prs_struct *outgoing_packet, int padding)
+static BOOL create_auth_hdr(prs_struct *outgoing_packet,
+ int auth_type,
+ int auth_level, int padding)
{
RPC_HDR_AUTH hdr_auth;
- init_rpc_hdr_auth(&hdr_auth, NETSEC_AUTH_TYPE,
- NETSEC_AUTH_LEVEL, padding, 1);
+ init_rpc_hdr_auth(&hdr_auth, auth_type, auth_level,
+ padding, 1);
if(!smb_io_rpc_hdr_auth("hdr_auth", &hdr_auth,
outgoing_packet, 0)) {
DEBUG(0,("create_auth_hdr:Failed to marshal RPC_HDR_AUTH.\n"));
@@ -941,30 +915,6 @@ static BOOL create_netsec_auth_hdr(prs_struct *outgoing_packet, int padding)
return True;
}
-/*******************************************************************
- Puts auth data into an rpc request.
- ********************************************************************/
-
-static BOOL create_auth_data(struct cli_state *cli, uint32 crc32,
- prs_struct *outgoing_packet)
-{
- char *pdata_out = prs_data_p(outgoing_packet);
- RPC_AUTH_NTLMSSP_CHK chk;
- uint32 current_offset = prs_offset(outgoing_packet);
-
- init_rpc_auth_ntlmssp_chk(&chk, NTLMSSP_SIGN_VERSION,
- crc32, cli->ntlmssp_seq_num++);
- if(!smb_io_rpc_auth_ntlmssp_chk("auth_sign", &chk,
- outgoing_packet, 0)) {
- DEBUG(0,("create_auth_data: Failed to marshal RPC_AUTH_NTLMSSP_CHK.\n"));
- return False;
- }
- NTLMSSPcalc_ap(cli, (unsigned char*)
- &pdata_out[current_offset+4],
- RPC_AUTH_NTLMSSP_CHK_LEN - 4);
- return True;
-}
-
/**
* Send a request on an RPC pipe and get a response.
*
@@ -975,43 +925,60 @@ static BOOL create_auth_data(struct cli_state *cli, uint32 crc32,
BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
prs_struct *data, prs_struct *rdata)
{
- uint32 auth_len, max_data, data_left, data_sent;
+ uint32 auth_len, real_auth_len, auth_hdr_len, max_data, data_left, data_sent;
+ NTSTATUS nt_status;
BOOL ret = False;
- BOOL auth_verify, auth_seal, auth_schannel;
uint32 callid = 0;
fstring dump_name;
- auth_verify = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SIGN) != 0);
- auth_seal = ((cli->ntlmssp_srv_flgs & NTLMSSP_NEGOTIATE_SEAL) != 0);
- auth_schannel = (cli->saved_netlogon_pipe_fnum != 0);
-
auth_len = 0;
+ real_auth_len = 0;
+ auth_hdr_len = 0;
- if (auth_verify)
- auth_len = RPC_AUTH_NTLMSSP_CHK_LEN;
-
- if (auth_schannel)
- auth_len = RPC_AUTH_NETSEC_CHK_LEN;
+ if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
+ if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+ auth_len = RPC_AUTH_NTLMSSP_CHK_LEN;
+ }
+ if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
+ auth_len = RPC_AUTH_NETSEC_CHK_LEN;
+ }
+ auth_hdr_len = RPC_HDR_AUTH_LEN;
+ }
/*
* calc how much actual data we can send in a PDU fragment
*/
max_data = cli->max_xmit_frag - RPC_HEADER_LEN - RPC_HDR_REQ_LEN -
- (auth_verify ? RPC_HDR_AUTH_LEN : 0) - auth_len - 8;
-
+ auth_hdr_len - auth_len - 8;
+
for (data_left = prs_offset(data), data_sent = 0; data_left > 0;) {
prs_struct outgoing_packet;
+ prs_struct sec_blob;
uint32 data_len, send_size;
uint8 flags = 0;
- uint32 crc32 = 0;
uint32 auth_padding = 0;
RPC_AUTH_NETSEC_CHK verf;
+ DATA_BLOB sign_blob;
/*
* how much will we send this time
*/
send_size = MIN(data_left, max_data);
+ if (!prs_init(&sec_blob, send_size, /* will need at least this much */
+ cli->mem_ctx, MARSHALL)) {
+ DEBUG(0,("Could not malloc %u bytes",
+ send_size+auth_padding));
+ return False;
+ }
+
+ if(!prs_append_some_prs_data(&sec_blob, data,
+ data_sent, send_size)) {
+ DEBUG(0,("Failed to append data to netsec blob\n"));
+ prs_mem_free(&sec_blob);
+ return False;
+ }
+
/*
* NT expects the data that is sealed to be 8-byte
* aligned. The padding must be encrypted as well and
@@ -1020,14 +987,105 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
* be stored in the auth header.
*/
- if (auth_schannel) {
- if (send_size % 8)
- auth_padding = 8 - (send_size % 8);
+ if (cli->pipe_auth_flags) {
+ size_t data_and_padding_size;
+ prs_align_uint64(&sec_blob);
+ int auth_type = 0;
+ int auth_level = 0;
+
+ if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) {
+ auth_level = RPC_PIPE_AUTH_SEAL_LEVEL;
+ } else if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
+ auth_level = RPC_PIPE_AUTH_SIGN_LEVEL;
+ }
+
+ if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
+ auth_type = NETSEC_AUTH_TYPE;
+ } else if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+ auth_type = NTLMSSP_AUTH_TYPE;
+ }
+
+ data_and_padding_size = prs_offset(&sec_blob);
+ auth_padding = data_and_padding_size - send_size;
+
+ /* insert the auth header */
+
+ if(!create_auth_hdr(&sec_blob, auth_type, auth_level, auth_padding)) {
+ prs_mem_free(&sec_blob);
+ return False;
+ }
+
+ /* create an NTLMSSP signature */
+ if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+ /*
+ * Seal the outgoing data if requested.
+ */
+ if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) {
+
+ nt_status = ntlmssp_client_seal_packet(cli->ntlmssp_pipe_state,
+ (unsigned char*)prs_data_p(&sec_blob),
+ data_and_padding_size,
+ &sign_blob);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ prs_mem_free(&sec_blob);
+ return False;
+ }
+ }
+ else if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
+
+ nt_status = ntlmssp_client_sign_packet(cli->ntlmssp_pipe_state,
+ (unsigned char*)prs_data_p(&sec_blob),
+ data_and_padding_size, &sign_blob);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ prs_mem_free(&sec_blob);
+ return False;
+ }
+ }
+
+
+ /* write auth footer onto the packet */
+ real_auth_len = sign_blob.length;
+
+ prs_copy_data_in(&sec_blob, sign_blob.data, sign_blob.length);
+ data_blob_free(&sign_blob);
+
+ }
+ else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
+ static const uchar netsec_sig[8] = NETSEC_SIGNATURE;
+ static const uchar nullbytes[8] = { 0,0,0,0,0,0,0,0 };
+ size_t parse_offset_marker;
+ if ((cli->auth_info.seq_num & 1) != 0) {
+ DEBUG(0,("SCHANNEL ERROR: seq_num must be even in client (seq_num=%d)\n",
+ cli->auth_info.seq_num));
+ }
+
+ DEBUG(10,("SCHANNEL seq_num=%d\n", cli->auth_info.seq_num));
+
+ init_rpc_auth_netsec_chk(&verf, netsec_sig, nullbytes,
+ nullbytes, nullbytes);
+
+ netsec_encode(&cli->auth_info,
+ cli->pipe_auth_flags,
+ SENDER_IS_INITIATOR,
+ &verf,
+ prs_data_p(&sec_blob),
+ data_and_padding_size);
+
+ cli->auth_info.seq_num++;
+
+ /* write auth footer onto the packet */
+
+ parse_offset_marker = prs_offset(&sec_blob);
+ if (!smb_io_rpc_auth_netsec_chk("", &verf,
+ &sec_blob, 0)) {
+ prs_mem_free(&sec_blob);
+ return False;
+ }
+ real_auth_len = prs_offset(&sec_blob) - parse_offset_marker;
+ }
}
- data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + send_size +
- ((auth_verify|auth_schannel) ? RPC_HDR_AUTH_LEN : 0) +
- auth_len + auth_padding;
+ data_len = RPC_HEADER_LEN + RPC_HDR_REQ_LEN + prs_offset(&sec_blob);
/*
* Malloc parse struct to hold it (and enough for alignments).
@@ -1047,128 +1105,23 @@ BOOL rpc_api_pipe_req(struct cli_state *cli, uint8 op_num,
* Write out the RPC header and the request header.
*/
if(!(callid = create_rpc_request(&outgoing_packet, op_num,
- data_len, auth_len, flags,
+ data_len, real_auth_len, flags,
callid, data_left))) {
DEBUG(0,("rpc_api_pipe_req: Failed to create RPC request.\n"));
prs_mem_free(&outgoing_packet);
+ prs_mem_free(&sec_blob);
return False;
}
- /*
- * Seal the outgoing data if requested.
- */
- if (auth_seal) {
- crc32 = crc32_calc_buffer(prs_data_p(data) + data_sent,
- send_size);
- NTLMSSPcalc_ap(cli, (unsigned char*)prs_data_p(data) +
- data_sent, send_size);
- }
-
- /*
- * Now copy the data into the outgoing packet.
- */
-
- if (auth_schannel) {
- static const uchar netsec_sig[8] = NETSEC_SIGNATURE;
- static const uchar nullbytes[8] = { 0,0,0,0,0,0,0,0 };
- uchar sign[8];
- prs_struct netsec_blob;
-
- if ((cli->auth_info.seq_num & 1) != 0) {
- DEBUG(0,("SCHANNEL ERROR: seq_num must be even in client (seq_num=%d)\n",
- cli->auth_info.seq_num));
- }
-
- DEBUG(10,("SCHANNEL seq_num=%d\n", cli->auth_info.seq_num));
-
- RSIVAL(sign, 0, cli->auth_info.seq_num);
- SIVAL(sign, 4, 0x80);
-
- if (!prs_init(&netsec_blob, send_size+auth_padding,
- cli->mem_ctx, MARSHALL)) {
- DEBUG(0,("Could not malloc %u bytes",
- send_size+auth_padding));
- prs_mem_free(&outgoing_packet);
- return False;
- }
-
- if(!prs_append_some_prs_data(&netsec_blob, data,
- data_sent, send_size)) {
- DEBUG(0,("Failed to append data to netsec blob\n"));
- prs_mem_free(&outgoing_packet);
- return False;
- }
-
- netsec_blob.align = 8;
-
- if (!prs_align(&netsec_blob)) {
- DEBUG(0,("Could not align netsec blob\n"));
- prs_mem_free(&outgoing_packet);
- return False;
- }
-
- init_rpc_auth_netsec_chk(&verf, netsec_sig, nullbytes,
- sign, nullbytes);
-
- netsec_encode(&cli->auth_info, &verf,
- prs_data_p(&netsec_blob),
- prs_data_size(&netsec_blob));
-
- prs_append_prs_data(&outgoing_packet, &netsec_blob);
- prs_mem_free(&netsec_blob);
-
- cli->auth_info.seq_num++;
-
- } else {
- if(!prs_append_some_prs_data(&outgoing_packet, data,
- data_sent, send_size)) {
- DEBUG(0,("rpc_api_pipe_req: Failed to append "
- "data to outgoing packet.\n"));
- prs_mem_free(&outgoing_packet);
- return False;
- }
- }
-
- /*
- * Add a trailing auth_verifier if needed.
- */
- if (auth_seal || auth_verify) {
- if(!create_ntlmssp_auth_hdr(&outgoing_packet, auth_verify)) {
- prs_mem_free(&outgoing_packet);
- return False;
- }
- }
-
- /*
- * Finally the auth data itself.
- */
- if (auth_verify) {
- if (!create_auth_data(cli, crc32, &outgoing_packet)) {
- prs_mem_free(&outgoing_packet);
- return False;
- }
- }
-
- if (auth_schannel) {
-
- if (!create_netsec_auth_hdr(&outgoing_packet,
- auth_padding)) {
- prs_mem_free(&outgoing_packet);
- return False;
- }
-
- if (!smb_io_rpc_auth_netsec_chk("", &verf,
- &outgoing_packet, 0)) {
- prs_mem_free(&outgoing_packet);
- return False;
- }
- }
+ prs_append_prs_data(&outgoing_packet, &sec_blob);
+ prs_mem_free(&sec_blob);
DEBUG(100,("data_len: %x data_calc_len: %x\n", data_len,
prs_offset(&outgoing_packet)));
if (flags & RPC_FLG_LAST)
- ret = rpc_api_pipe(cli, &outgoing_packet, rdata);
+ ret = rpc_api_pipe(cli, &outgoing_packet,
+ rdata, RPC_RESPONSE);
else {
cli_write(cli, cli->nt_pipe_fnum, 0x0008,
prs_data_p(&outgoing_packet),
@@ -1352,84 +1305,23 @@ static BOOL check_bind_response(RPC_HDR_BA *hdr_ba, const int pipe_idx, RPC_IFAC
static BOOL rpc_send_auth_reply(struct cli_state *cli, prs_struct *rdata, uint32 rpc_call_id)
{
- RPC_HDR_AUTH rhdr_auth;
- RPC_AUTH_VERIFIER rhdr_verf;
- RPC_AUTH_NTLMSSP_CHAL rhdr_chal;
- char buffer[MAX_PDU_FRAG_LEN];
prs_struct rpc_out;
ssize_t ret;
- unsigned char p24[24];
- unsigned char lm_owf[24];
- unsigned char lm_hash[16];
+ prs_init(&rpc_out, RPC_HEADER_LEN + RPC_HDR_AUTHA_LEN, /* need at least this much */
+ cli->mem_ctx, MARSHALL);
- if(!smb_io_rpc_hdr_auth("", &rhdr_auth, rdata, 0)) {
- DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_HDR_AUTH.\n"));
- return False;
- }
- if(!smb_io_rpc_auth_verifier("", &rhdr_verf, rdata, 0)) {
- DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_AUTH_VERIFIER.\n"));
- return False;
- }
- if(!smb_io_rpc_auth_ntlmssp_chal("", &rhdr_chal, rdata, 0)) {
- DEBUG(0,("rpc_send_auth_reply: Failed to unmarshall RPC_AUTH_NTLMSSP_CHAL.\n"));
- return False;
- }
-
- cli->ntlmssp_cli_flgs = rhdr_chal.neg_flags;
-
- pwd_make_lm_nt_owf(&cli->pwd, rhdr_chal.challenge);
-
- prs_init(&rpc_out, 0, cli->mem_ctx, MARSHALL);
-
- prs_give_memory( &rpc_out, buffer, sizeof(buffer), False);
-
- create_rpc_bind_resp(&cli->pwd, cli->domain,
- cli->user_name, global_myname(),
- cli->ntlmssp_cli_flgs, rpc_call_id,
+ create_rpc_bind_resp(cli, rpc_call_id,
&rpc_out);
-
- pwd_get_lm_nt_owf(&cli->pwd, lm_owf, NULL);
- pwd_get_lm_nt_16(&cli->pwd, lm_hash, NULL);
-
- NTLMSSPOWFencrypt(lm_hash, lm_owf, p24);
-
- {
- unsigned char j = 0;
- int ind;
- unsigned char k2[8];
-
- memcpy(k2, p24, 5);
- k2[5] = 0xe5;
- k2[6] = 0x38;
- k2[7] = 0xb0;
-
- for (ind = 0; ind < 256; ind++)
- cli->ntlmssp_hash[ind] = (unsigned char)ind;
-
- for( ind = 0; ind < 256; ind++) {
- unsigned char tc;
-
- j += (cli->ntlmssp_hash[ind] + k2[ind%8]);
-
- tc = cli->ntlmssp_hash[ind];
- cli->ntlmssp_hash[ind] = cli->ntlmssp_hash[j];
- cli->ntlmssp_hash[j] = tc;
- }
-
- cli->ntlmssp_hash[256] = 0;
- cli->ntlmssp_hash[257] = 0;
- }
-
- memset((char *)lm_hash, '\0', sizeof(lm_hash));
if ((ret = cli_write(cli, cli->nt_pipe_fnum, 0x8, prs_data_p(&rpc_out),
0, (size_t)prs_offset(&rpc_out))) != (ssize_t)prs_offset(&rpc_out)) {
DEBUG(0,("rpc_send_auth_reply: cli_write failed. Return was %d\n", (int)ret));
+ prs_mem_free(&rpc_out);
return False;
}
- cli->ntlmssp_srv_flgs = rhdr_chal.neg_flags;
+ prs_mem_free(&rpc_out);
return True;
}
@@ -1437,14 +1329,12 @@ static BOOL rpc_send_auth_reply(struct cli_state *cli, prs_struct *rdata, uint32
Do an rpc bind.
****************************************************************************/
-static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_name,
- BOOL do_netsec)
+static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_name)
{
RPC_IFACE abstract;
RPC_IFACE transfer;
prs_struct rpc_out;
prs_struct rdata;
- BOOL do_auth = (cli->ntlmssp_cli_flgs != 0);
uint32 rpc_call_id;
char buffer[MAX_PDU_FRAG_LEN];
@@ -1466,16 +1356,54 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
rpc_call_id = get_rpc_call_id();
+ if (cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
+ NTSTATUS nt_status;
+ fstring password;
+
+ DEBUG(5, ("NTLMSSP authenticated pipe selected\n"));
+
+ nt_status = ntlmssp_client_start(&cli->ntlmssp_pipe_state);
+
+ if (!NT_STATUS_IS_OK(nt_status))
+ return False;
+
+ nt_status = ntlmssp_set_username(cli->ntlmssp_pipe_state,
+ cli->user_name);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return False;
+
+ nt_status = ntlmssp_set_domain(cli->ntlmssp_pipe_state,
+ cli->domain);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return False;
+
+ pwd_get_cleartext(&cli->pwd, password);
+ nt_status = ntlmssp_set_password(cli->ntlmssp_pipe_state,
+ password);
+ if (!NT_STATUS_IS_OK(nt_status))
+ return False;
+
+ if (cli->pipe_auth_flags & AUTH_PIPE_SIGN) {
+ cli->ntlmssp_pipe_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ }
+
+ if (cli->pipe_auth_flags & AUTH_PIPE_SEAL) {
+ cli->ntlmssp_pipe_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
+ }
+ } else if (cli->pipe_auth_flags & AUTH_PIPE_NETSEC) {
+ cli->auth_info.seq_num = 0;
+ }
+
/* Marshall the outgoing data. */
- create_rpc_bind_req(&rpc_out, do_auth, do_netsec, rpc_call_id,
+ create_rpc_bind_req(cli, &rpc_out, rpc_call_id,
&abstract, &transfer,
- global_myname(), cli->domain, cli->ntlmssp_cli_flgs);
+ global_myname(), cli->domain);
/* Initialize the incoming data struct. */
prs_init(&rdata, 0, cli->mem_ctx, UNMARSHALL);
/* send data on \PIPE\. receive a response */
- if (rpc_api_pipe(cli, &rpc_out, &rdata)) {
+ if (rpc_api_pipe(cli, &rpc_out, &rdata, RPC_BINDACK)) {
RPC_HDR_BA hdr_ba;
DEBUG(5, ("rpc_pipe_bind: rpc_api_pipe returned OK.\n"));
@@ -1501,15 +1429,17 @@ static BOOL rpc_pipe_bind(struct cli_state *cli, int pipe_idx, const char *my_na
* handshake.
*/
- if (do_auth && !rpc_send_auth_reply(cli, &rdata, rpc_call_id)) {
+ if ((cli->pipe_auth_flags & AUTH_PIPE_NTLMSSP)
+ && !rpc_send_auth_reply(cli, &rdata, rpc_call_id)) {
DEBUG(0,("rpc_pipe_bind: rpc_send_auth_reply failed.\n"));
prs_mem_free(&rdata);
return False;
}
+ prs_mem_free(&rdata);
+ return True;
}
- prs_mem_free(&rdata);
- return True;
+ return False;
}
/****************************************************************************
@@ -1557,7 +1487,7 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
/******************* bind request on pipe *****************/
- if (!rpc_pipe_bind(cli, pipe_idx, global_myname(), False)) {
+ if (!rpc_pipe_bind(cli, pipe_idx, global_myname())) {
DEBUG(2,("cli_nt_session_open: rpc bind to %s failed\n",
get_pipe_name_from_index(pipe_idx)));
cli_close(cli, cli->nt_pipe_fnum);
@@ -1589,15 +1519,19 @@ BOOL cli_nt_session_open(struct cli_state *cli, const int pipe_idx)
/****************************************************************************
Open a session to the NETLOGON pipe using schannel.
+
+ (Assumes that the netlogon pipe is already open)
****************************************************************************/
NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
- const char *trust_password)
+ const uchar trust_password[16])
{
- NTSTATUS result;
+ NTSTATUS result;
uint32 neg_flags = 0x000001ff;
int fnum;
+ cli_nt_netlogon_netsec_session_close(cli);
+
if (lp_client_schannel() != False)
neg_flags |= NETLOGON_NEG_SCHANNEL;
@@ -1620,22 +1554,27 @@ NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
if ((lp_client_schannel() == False) ||
((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
return NT_STATUS_OK;
+
+ /* keep the existing connection to NETLOGON open */
+
}
/* Server offered schannel, so try it. */
- cli->auth_info.seq_num = 0;
memcpy(cli->auth_info.sess_key, cli->sess_key,
sizeof(cli->auth_info.sess_key));
cli->saved_netlogon_pipe_fnum = cli->nt_pipe_fnum;
+ cli->pipe_auth_flags = AUTH_PIPE_NETSEC;
+ cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
+ cli->pipe_auth_flags |= AUTH_PIPE_SEAL;
+
if (cli->capabilities & CAP_NT_SMBS) {
/* The secure channel connection must be opened on the same
session (TCP connection) as the one the challenge was
requested from. */
-
if ((fnum = cli_nt_create(cli, PIPE_NETLOGON_PLAIN,
DESIRED_ACCESS_PIPE)) == -1) {
DEBUG(0,("cli_nt_create failed to %s machine %s. "
@@ -1666,8 +1605,11 @@ NTSTATUS cli_nt_establish_netlogon(struct cli_state *cli, int sec_chan,
return NT_STATUS_UNSUCCESSFUL;
}
}
-
- if (!rpc_pipe_bind(cli, PI_NETLOGON, global_myname(), True)) {
+
+ /* doing schannel, not per-user auth */
+ cli->pipe_auth_flags = AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN | AUTH_PIPE_SEAL;
+
+ if (!rpc_pipe_bind(cli, PI_NETLOGON, global_myname())) {
DEBUG(2,("rpc bind to %s failed\n", PIPE_NETLOGON));
cli_close(cli, cli->nt_pipe_fnum);
return NT_STATUS_UNSUCCESSFUL;
@@ -1683,16 +1625,3 @@ const char *cli_pipe_get_name(struct cli_state *cli)
}
-/****************************************************************************
-close the session
-****************************************************************************/
-
-void cli_nt_session_close(struct cli_state *cli)
-{
- if (cli->saved_netlogon_pipe_fnum != 0) {
- cli_close(cli, cli->saved_netlogon_pipe_fnum);
- cli->saved_netlogon_pipe_fnum = 0;
- }
- cli_close(cli, cli->nt_pipe_fnum);
- cli->nt_pipe_fnum = 0;
-}
diff --git a/source3/rpc_parse/parse_prs.c b/source3/rpc_parse/parse_prs.c
index 88150c718b..efd4914c66 100644
--- a/source3/rpc_parse/parse_prs.c
+++ b/source3/rpc_parse/parse_prs.c
@@ -1378,141 +1378,221 @@ static void netsechash(uchar * key, uchar * data, int data_len)
}
}
-void dump_data_pw(const char *msg, const uchar * data, size_t len)
+
+/*******************************************************************
+ Create a digest over the entire packet (including the data), and
+ MD5 it with the session key.
+ ********************************************************************/
+static void netsec_digest(struct netsec_auth_struct *a,
+ int auth_flags,
+ RPC_AUTH_NETSEC_CHK * verf,
+ char *data, size_t data_len,
+ uchar digest_final[16])
{
-#ifdef DEBUG_PASSWORD
- DEBUG(11, ("%s", msg));
- if (data != NULL && len > 0)
- {
- dump_data(11, data, len);
+ uchar whole_packet_digest[16];
+ static uchar zeros[4];
+ struct MD5Context ctx3;
+
+ /* verfiy the signature on the packet by MD5 over various bits */
+ MD5Init(&ctx3);
+ /* use our sequence number, which ensures the packet is not
+ out of order */
+ MD5Update(&ctx3, zeros, sizeof(zeros));
+ MD5Update(&ctx3, verf->sig, sizeof(verf->sig));
+ if (auth_flags & AUTH_PIPE_SEAL) {
+ MD5Update(&ctx3, verf->data8, sizeof(verf->data8));
}
-#endif
+ MD5Update(&ctx3, data, data_len);
+ MD5Final(whole_packet_digest, &ctx3);
+ dump_data_pw("whole_packet_digest:\n", whole_packet_digest, sizeof(whole_packet_digest));
+
+ /* MD5 this result and the session key, to prove that
+ only a valid client could had produced this */
+ hmac_md5(a->sess_key, whole_packet_digest, sizeof(whole_packet_digest), digest_final);
}
-void netsec_encode(struct netsec_auth_struct *a,
- RPC_AUTH_NETSEC_CHK * verf, char *data, size_t data_len)
+/*******************************************************************
+ Calculate the key with which to encode the data payload
+ ********************************************************************/
+static void netsec_get_sealing_key(struct netsec_auth_struct *a,
+ RPC_AUTH_NETSEC_CHK *verf,
+ uchar sealing_key[16])
{
- uchar dataN[4];
- uchar digest1[16];
- struct MD5Context ctx3;
+ static uchar zeros[4];
+ uchar digest2[16];
uchar sess_kf0[16];
int i;
- SIVAL(dataN, 0, 0);
-
for (i = 0; i < sizeof(sess_kf0); i++) {
sess_kf0[i] = a->sess_key[i] ^ 0xf0;
}
+
+ dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0));
+
+ /* MD5 of sess_kf0 and the high bytes of the sequence number */
+ hmac_md5(sess_kf0, zeros, 0x4, digest2);
+ dump_data_pw("digest2:\n", digest2, sizeof(digest2));
+
+ /* MD5 of the above result, plus 8 bytes of sequence number */
+ hmac_md5(digest2, verf->seq_num, sizeof(verf->seq_num), sealing_key);
+ dump_data_pw("sealing_key:\n", sealing_key, 16);
+}
- DEBUG(10,("SCHANNEL: netsec_encode seq_num=%d data_len=%d\n", a->seq_num, data_len));
- dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
- dump_data_pw("a->seq_num :\n", dataN, sizeof(dataN));
+/*******************************************************************
+ Encode or Decode the sequence number (which is symmetric)
+ ********************************************************************/
+static void netsec_deal_with_seq_num(struct netsec_auth_struct *a,
+ RPC_AUTH_NETSEC_CHK *verf)
+{
+ static uchar zeros[4];
+ uchar sequence_key[16];
+ uchar digest1[16];
- MD5Init(&ctx3);
- MD5Update(&ctx3, dataN, 0x4);
- MD5Update(&ctx3, verf->sig, 8);
+ hmac_md5(a->sess_key, zeros, sizeof(zeros), digest1);
+ dump_data_pw("(sequence key) digest1:\n", digest1, sizeof(digest1));
- MD5Update(&ctx3, verf->data8, 8);
+ hmac_md5(digest1, verf->packet_digest, 8, sequence_key);
- dump_data_pw("verf->data8:\n", verf->data8, sizeof(verf->data8));
- dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0));
+ dump_data_pw("sequence_key:\n", sequence_key, sizeof(sequence_key));
- hmac_md5(sess_kf0, dataN, 0x4, digest1);
- dump_data_pw("digest1 (ebp-8):\n", digest1, sizeof(digest1));
- hmac_md5(digest1, verf->data3, 8, digest1);
- dump_data_pw("netsechashkey:\n", digest1, sizeof(digest1));
- netsechash(digest1, verf->data8, 8);
+ dump_data_pw("seq_num (before):\n", verf->seq_num, sizeof(verf->seq_num));
+ netsechash(sequence_key, verf->seq_num, 8);
+ dump_data_pw("seq_num (after):\n", verf->seq_num, sizeof(verf->seq_num));
+}
- dump_data_pw("verf->data8:\n", verf->data8, sizeof(verf->data8));
- dump_data_pw("data :\n", data, data_len);
- MD5Update(&ctx3, data, data_len);
+/*******************************************************************
+ Encode a blob of data using the netsec (schannel) alogrithm, also produceing
+ a checksum over the original data. We currently only support
+ signing and sealing togeather - the signing-only code is close, but not
+ quite compatible with what MS does.
+ ********************************************************************/
+void netsec_encode(struct netsec_auth_struct *a, int auth_flags,
+ enum netsec_direction direction,
+ RPC_AUTH_NETSEC_CHK * verf, char *data, size_t data_len)
+{
+ uchar digest_final[16];
- {
- char digest_tmp[16];
- char digest2[16];
- MD5Final(digest_tmp, &ctx3);
- hmac_md5(a->sess_key, digest_tmp, 16, digest2);
- dump_data_pw("digest_tmp:\n", digest_tmp, sizeof(digest_tmp));
- dump_data_pw("digest:\n", digest2, sizeof(digest2));
- memcpy(verf->data1, digest2, sizeof(verf->data1));
+ DEBUG(10,("SCHANNEL: netsec_encode seq_num=%d data_len=%d\n", a->seq_num, data_len));
+ dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
+
+ RSIVAL(verf->seq_num, 0, a->seq_num);
+
+ switch (direction) {
+ case SENDER_IS_INITIATOR:
+ SIVAL(verf->seq_num, 4, 0x80);
+ break;
+ case SENDER_IS_ACCEPTOR:
+ SIVAL(verf->seq_num, 4, 0x0);
+ break;
}
- netsechash(digest1, data, data_len);
- dump_data_pw("data:\n", data, data_len);
+ dump_data_pw("verf->seq_num:\n", verf->seq_num, sizeof(verf->seq_num));
- hmac_md5(a->sess_key, dataN, 0x4, digest1);
- dump_data_pw("ctx:\n", digest1, sizeof(digest1));
+ /* produce a digest of the packet to prove it's legit (before we seal it) */
+ netsec_digest(a, auth_flags, verf, data, data_len, digest_final);
+ memcpy(verf->packet_digest, digest_final, sizeof(verf->packet_digest));
- hmac_md5(digest1, verf->data1, 8, digest1);
+ if (auth_flags & AUTH_PIPE_SEAL) {
+ uchar sealing_key[16];
- dump_data_pw("netsechashkey:\n", digest1, sizeof(digest1));
+ /* get the key to encode the data with */
+ netsec_get_sealing_key(a, verf, sealing_key);
- dump_data_pw("verf->data3:\n", verf->data3, sizeof(verf->data3));
- netsechash(digest1, verf->data3, 8);
- dump_data_pw("verf->data3:\n", verf->data3, sizeof(verf->data3));
+ /* encode the verification data */
+ dump_data_pw("verf->data8:\n", verf->data8, sizeof(verf->data8));
+ netsechash(sealing_key, verf->data8, 8);
+
+ dump_data_pw("verf->data8_enc:\n", verf->data8, sizeof(verf->data8));
+
+ /* encode the packet payload */
+ dump_data_pw("data:\n", data, data_len);
+ netsechash(sealing_key, data, data_len);
+ dump_data_pw("data_enc:\n", data, data_len);
+ }
+
+ /* encode the sequence number (key based on packet digest) */
+ /* needs to be done after the sealing, as the original version
+ is used in the sealing stuff... */
+ netsec_deal_with_seq_num(a, verf);
return;
}
-BOOL netsec_decode(struct netsec_auth_struct *a,
+/*******************************************************************
+ Decode a blob of data using the netsec (schannel) alogrithm, also verifiying
+ a checksum over the original data. We currently can verify signed messages,
+ as well as decode sealed messages
+ ********************************************************************/
+
+BOOL netsec_decode(struct netsec_auth_struct *a, int auth_flags,
+ enum netsec_direction direction,
RPC_AUTH_NETSEC_CHK * verf, char *data, size_t data_len)
{
- uchar dataN[4];
- uchar digest1[16];
- struct MD5Context ctx3;
- uchar sess_kf0[16];
- int i;
-
- SIVAL(dataN, 0, 0);
-
- for (i = 0; i < sizeof(sess_kf0); i++) {
- sess_kf0[i] = a->sess_key[i] ^ 0xf0;
+ uchar digest_final[16];
+
+ /* Create the expected sequence number for comparison */
+ uchar seq_num[8];
+ RSIVAL(seq_num, 0, a->seq_num);
+
+ switch (direction) {
+ case SENDER_IS_INITIATOR:
+ SIVAL(seq_num, 4, 0x80);
+ break;
+ case SENDER_IS_ACCEPTOR:
+ SIVAL(seq_num, 4, 0x0);
+ break;
}
DEBUG(10,("SCHANNEL: netsec_decode seq_num=%d data_len=%d\n", a->seq_num, data_len));
dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
- dump_data_pw("a->seq_num :\n", dataN, sizeof(dataN));
- hmac_md5(a->sess_key, dataN, 0x4, digest1);
- dump_data_pw("ctx:\n", digest1, sizeof(digest1));
-
- hmac_md5(digest1, verf->data1, 8, digest1);
-
- dump_data_pw("netsechashkey:\n", digest1, sizeof(digest1));
- dump_data_pw("verf->data3:\n", verf->data3, sizeof(verf->data3));
- netsechash(digest1, verf->data3, 8);
- dump_data_pw("verf->data3_dec:\n", verf->data3, sizeof(verf->data3));
-
- MD5Init(&ctx3);
- MD5Update(&ctx3, dataN, 0x4);
- MD5Update(&ctx3, verf->sig, 8);
-
- dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0));
- hmac_md5(sess_kf0, dataN, 0x4, digest1);
- dump_data_pw("digest1 (ebp-8):\n", digest1, sizeof(digest1));
- hmac_md5(digest1, verf->data3, 8, digest1);
- dump_data_pw("netsechashkey:\n", digest1, sizeof(digest1));
+ dump_data_pw("seq_num:\n", seq_num, sizeof(seq_num));
- dump_data_pw("verf->data8:\n", verf->data8, sizeof(verf->data8));
- netsechash(digest1, verf->data8, 8);
- dump_data_pw("verf->data8_dec:\n", verf->data8, sizeof(verf->data8));
- MD5Update(&ctx3, verf->data8, 8);
+ /* extract the sequence number (key based on supplied packet digest) */
+ /* needs to be done before the sealing, as the original version
+ is used in the sealing stuff... */
+ netsec_deal_with_seq_num(a, verf);
- dump_data_pw("data :\n", data, data_len);
- netsechash(digest1, data, data_len);
- dump_data_pw("datadec:\n", data, data_len);
+ if (memcmp(verf->seq_num, seq_num, sizeof(seq_num))) {
+ /* don't even bother with the below if the sequence number is out */
+ /* The sequence number is MD5'ed with a key based on the whole-packet
+ digest, as supplied by the client. We check that it's a valid
+ checksum after the decode, below
+ */
+ return False;
+ }
- MD5Update(&ctx3, data, data_len);
- {
- uchar digest_tmp[16];
- MD5Final(digest_tmp, &ctx3);
- hmac_md5(a->sess_key, digest_tmp, 16, digest1);
- dump_data_pw("digest_tmp:\n", digest_tmp, sizeof(digest_tmp));
+ if (auth_flags & AUTH_PIPE_SEAL) {
+ uchar sealing_key[16];
+
+ /* get the key to extract the data with */
+ netsec_get_sealing_key(a, verf, sealing_key);
+
+ /* extract the verification data */
+ dump_data_pw("verf->data8:\n", verf->data8,
+ sizeof(verf->data8));
+ netsechash(sealing_key, verf->data8, 8);
+
+ dump_data_pw("verf->data8_dec:\n", verf->data8,
+ sizeof(verf->data8));
+
+ /* extract the packet payload */
+ dump_data_pw("data :\n", data, data_len);
+ netsechash(sealing_key, data, data_len);
+ dump_data_pw("datadec:\n", data, data_len);
}
- dump_data_pw("digest:\n", digest1, sizeof(digest1));
- dump_data_pw("verf->data1:\n", verf->data1, sizeof(verf->data1));
+ /* digest includes 'data' after unsealing */
+ netsec_digest(a, auth_flags, verf, data, data_len, digest_final);
- return memcmp(digest1, verf->data1, sizeof(verf->data1)) == 0;
+ dump_data_pw("Calculated digest:\n", digest_final,
+ sizeof(digest_final));
+ dump_data_pw("verf->packet_digest:\n", verf->packet_digest,
+ sizeof(verf->packet_digest));
+
+ /* compare - if the client got the same result as us, then
+ it must know the session key */
+ return (memcmp(digest_final, verf->packet_digest,
+ sizeof(verf->packet_digest)) == 0);
}
diff --git a/source3/rpc_parse/parse_rpc.c b/source3/rpc_parse/parse_rpc.c
index be3a04e31c..34ba62caa9 100644
--- a/source3/rpc_parse/parse_rpc.c
+++ b/source3/rpc_parse/parse_rpc.c
@@ -603,15 +603,6 @@ BOOL smb_io_rpc_hdr_autha(const char *desc, RPC_HDR_AUTHA *rai, prs_struct *ps,
}
/*******************************************************************
- Checks an RPC_HDR_AUTH structure.
-********************************************************************/
-
-BOOL rpc_hdr_auth_chk(RPC_HDR_AUTH *rai)
-{
- return (rai->auth_type == NTLMSSP_AUTH_TYPE && rai->auth_level == NTLMSSP_AUTH_LEVEL);
-}
-
-/*******************************************************************
Inits an RPC_HDR_AUTH structure.
********************************************************************/
@@ -1088,9 +1079,10 @@ BOOL rpc_auth_ntlmssp_chk(RPC_AUTH_NTLMSSP_CHK *chk, uint32 crc32, uint32 seq_nu
chk->seq_num != seq_num)
{
DEBUG(5,("verify failed - crc %x ver %x seq %d\n",
- crc32, NTLMSSP_SIGN_VERSION, seq_num));
+ chk->crc32, chk->ver, chk->seq_num));
+
DEBUG(5,("verify expect - crc %x ver %x seq %d\n",
- chk->crc32, chk->ver, chk->seq_num));
+ crc32, NTLMSSP_SIGN_VERSION, seq_num));
return False;
}
return True;
@@ -1182,15 +1174,15 @@ creates an RPC_AUTH_NETSEC_CHK structure.
********************************************************************/
BOOL init_rpc_auth_netsec_chk(RPC_AUTH_NETSEC_CHK * chk,
const uchar sig[8],
- const uchar data1[8],
- const uchar data3[8], const uchar data8[8])
+ const uchar packet_digest[8],
+ const uchar seq_num[8], const uchar data8[8])
{
if (chk == NULL)
return False;
memcpy(chk->sig, sig, sizeof(chk->sig));
- memcpy(chk->data1, data1, sizeof(chk->data1));
- memcpy(chk->data3, data3, sizeof(chk->data3));
+ memcpy(chk->packet_digest, packet_digest, sizeof(chk->packet_digest));
+ memcpy(chk->seq_num, seq_num, sizeof(chk->seq_num));
memcpy(chk->data8, data8, sizeof(chk->data8));
return True;
@@ -1209,8 +1201,8 @@ BOOL smb_io_rpc_auth_netsec_chk(const char *desc, RPC_AUTH_NETSEC_CHK * chk,
depth++;
prs_uint8s(False, "sig ", ps, depth, chk->sig, sizeof(chk->sig));
- prs_uint8s(False, "data3", ps, depth, chk->data3, sizeof(chk->data3));
- prs_uint8s(False, "data1", ps, depth, chk->data1, sizeof(chk->data1));
+ prs_uint8s(False, "seq_num", ps, depth, chk->seq_num, sizeof(chk->seq_num));
+ prs_uint8s(False, "packet_digest", ps, depth, chk->packet_digest, sizeof(chk->packet_digest));
prs_uint8s(False, "data8", ps, depth, chk->data8, sizeof(chk->data8));
return True;
diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index f7663204b2..9a63ebc7a3 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -227,7 +227,7 @@ BOOL create_next_pdu(pipes_struct *p)
if (auth_seal || auth_verify) {
RPC_HDR_AUTH auth_info;
- init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL,
+ init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, RPC_PIPE_AUTH_SEAL_LEVEL,
(auth_verify ? RPC_HDR_AUTH_LEN : 0), (auth_verify ? 1 : 0));
if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
DEBUG(0,("create_next_pdu: failed to marshall RPC_HDR_AUTH.\n"));
@@ -263,11 +263,9 @@ BOOL create_next_pdu(pipes_struct *p)
prs_struct rverf;
prs_struct rauth;
- uchar sign[8];
-
data = prs_data_p(&outgoing_pdu) + data_pos;
- init_rpc_hdr_auth(&auth_info, NETSEC_AUTH_TYPE, NETSEC_AUTH_LEVEL,
+ init_rpc_hdr_auth(&auth_info, NETSEC_AUTH_TYPE, RPC_PIPE_AUTH_SEAL_LEVEL,
RPC_HDR_AUTH_LEN, 1);
if(!smb_io_rpc_hdr_auth("hdr_auth", &auth_info, &outgoing_pdu, 0)) {
@@ -284,12 +282,12 @@ BOOL create_next_pdu(pipes_struct *p)
p->netsec_auth.seq_num));
}
- RSIVAL(sign, 0, p->netsec_auth.seq_num);
- SIVAL(sign, 4, 0);
-
- init_rpc_auth_netsec_chk(&verf, netsec_sig, nullbytes, sign, nullbytes);
+ init_rpc_auth_netsec_chk(&verf, netsec_sig, nullbytes, nullbytes, nullbytes);
- netsec_encode(&p->netsec_auth, &verf, data, data_len);
+ netsec_encode(&p->netsec_auth,
+ AUTH_PIPE_NETSEC|AUTH_PIPE_SIGN|AUTH_PIPE_SEAL,
+ SENDER_IS_ACCEPTOR,
+ &verf, data, data_len);
smb_io_rpc_auth_netsec_chk("", &verf, &outgoing_pdu, 0);
@@ -458,6 +456,10 @@ failed authentication on named pipe %s.\n", domain, user_name, wks, p->name ));
p->ntlmssp_hash[256] = 0;
p->ntlmssp_hash[257] = 0;
}
+
+ dump_data_pw("NTLMSSP hash (v1)\n", p->ntlmssp_hash,
+ sizeof(p->ntlmssp_hash));
+
/* NTLMSSPhash(p->ntlmssp_hash, p24); */
p->ntlmssp_seq_num = 0;
@@ -546,7 +548,7 @@ BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *rpc_in_p)
return False;
}
- if (autha_info.auth_type != NTLMSSP_AUTH_TYPE || autha_info.auth_level != NTLMSSP_AUTH_LEVEL) {
+ if (autha_info.auth_type != NTLMSSP_AUTH_TYPE || autha_info.auth_level != RPC_PIPE_AUTH_SEAL_LEVEL) {
DEBUG(0,("api_pipe_bind_auth_resp: incorrect auth type (%d) or level (%d).\n",
(int)autha_info.auth_type, (int)autha_info.auth_level ));
return False;
@@ -1070,7 +1072,7 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
/*** Authentication info ***/
- init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, NTLMSSP_AUTH_LEVEL, RPC_HDR_AUTH_LEN, 1);
+ init_rpc_hdr_auth(&auth_info, NTLMSSP_AUTH_TYPE, RPC_PIPE_AUTH_SEAL_LEVEL, RPC_HDR_AUTH_LEN, 1);
if(!smb_io_rpc_hdr_auth("", &auth_info, &out_auth, 0)) {
DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_AUTH failed.\n"));
goto err_exit;
@@ -1105,7 +1107,7 @@ BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *rpc_in_p)
re-used from the auth2 the client did before. */
p->dc = last_dcinfo;
- init_rpc_hdr_auth(&auth_info, NETSEC_AUTH_TYPE, NETSEC_AUTH_LEVEL, RPC_HDR_AUTH_LEN, 1);
+ init_rpc_hdr_auth(&auth_info, NETSEC_AUTH_TYPE, RPC_PIPE_AUTH_SEAL_LEVEL, RPC_HDR_AUTH_LEN, 1);
if(!smb_io_rpc_hdr_auth("", &auth_info, &out_auth, 0)) {
DEBUG(0,("api_pipe_bind_req: marshalling of RPC_HDR_AUTH failed.\n"));
goto err_exit;
@@ -1226,7 +1228,14 @@ BOOL api_pipe_auth_process(pipes_struct *p, prs_struct *rpc_in)
* has already been consumed.
*/
char *data = prs_data_p(rpc_in) + RPC_HDR_REQ_LEN;
+ dump_data_pw("NTLMSSP hash (v1)\n", p->ntlmssp_hash,
+ sizeof(p->ntlmssp_hash));
+
+ dump_data_pw("Incoming RPC PDU (NTLMSSP sealed)\n",
+ data, data_len);
NTLMSSPcalc_p(p, (uchar*)data, data_len);
+ dump_data_pw("Incoming RPC PDU (NTLMSSP unsealed)\n",
+ data, data_len);
crc32 = crc32_calc_buffer(data, data_len);
}
@@ -1335,7 +1344,7 @@ BOOL api_pipe_netsec_process(pipes_struct *p, prs_struct *rpc_in)
}
if ((auth_info.auth_type != NETSEC_AUTH_TYPE) ||
- (auth_info.auth_level != NETSEC_AUTH_LEVEL)) {
+ (auth_info.auth_level != RPC_PIPE_AUTH_SEAL_LEVEL)) {
DEBUG(0,("Invalid auth info %d or level %d on schannel\n",
auth_info.auth_type, auth_info.auth_level));
return False;
@@ -1346,7 +1355,10 @@ BOOL api_pipe_netsec_process(pipes_struct *p, prs_struct *rpc_in)
return False;
}
- if (!netsec_decode(&p->netsec_auth, &netsec_chk,
+ if (!netsec_decode(&p->netsec_auth,
+ AUTH_PIPE_NETSEC|AUTH_PIPE_SIGN|AUTH_PIPE_SEAL,
+ SENDER_IS_INITIATOR,
+ &netsec_chk,
prs_data_p(rpc_in)+old_offset, data_len)) {
DEBUG(0,("failed to decode PDU\n"));
return False;
diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c
index 7c382a9813..af021962f5 100644
--- a/source3/rpcclient/rpcclient.c
+++ b/source3/rpcclient/rpcclient.c
@@ -319,6 +319,119 @@ static NTSTATUS cmd_quit(struct cli_state *cli, TALLOC_CTX *mem_ctx,
return NT_STATUS_OK; /* NOTREACHED */
}
+static NTSTATUS cmd_sign(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ if (cli->pipe_auth_flags == (AUTH_PIPE_NTLMSSP|AUTH_PIPE_SIGN)) {
+ return NT_STATUS_OK;
+ } else {
+ /* still have session, just need to use it again */
+ cli->pipe_auth_flags = AUTH_PIPE_NTLMSSP;
+ cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
+ if (cli->nt_pipe_fnum != 0)
+ cli_nt_session_close(cli);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_seal(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ if (cli->pipe_auth_flags == (AUTH_PIPE_NTLMSSP|AUTH_PIPE_SIGN|AUTH_PIPE_SEAL)) {
+ return NT_STATUS_OK;
+ } else {
+ /* still have session, just need to use it again */
+ cli->pipe_auth_flags = AUTH_PIPE_NTLMSSP;
+ cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
+ cli->pipe_auth_flags |= AUTH_PIPE_SEAL;
+ if (cli->nt_pipe_fnum != 0)
+ cli_nt_session_close(cli);
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_none(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ if (cli->pipe_auth_flags == 0) {
+ return NT_STATUS_OK;
+ } else {
+ /* still have session, just need to use it again */
+ cli->pipe_auth_flags = 0;
+ if (cli->nt_pipe_fnum != 0)
+ cli_nt_session_close(cli);
+ }
+ cli->pipe_auth_flags = 0;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cmd_schannel(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ int argc, const char **argv)
+{
+ uchar trust_password[16];
+ uint32 sec_channel_type;
+ uint32 neg_flags = 0x000001ff;
+ NTSTATUS result;
+ static uchar zeros[16];
+
+ /* Cleanup */
+
+ if ((memcmp(cli->auth_info.sess_key, zeros, sizeof(cli->auth_info.sess_key)) != 0)
+ && (cli->saved_netlogon_pipe_fnum != 0)) {
+ if (cli->pipe_auth_flags == (AUTH_PIPE_NETSEC|AUTH_PIPE_SIGN|AUTH_PIPE_SEAL)) {
+ return NT_STATUS_OK;
+ } else {
+ /* still have session, just need to use it again */
+ cli->pipe_auth_flags = AUTH_PIPE_NETSEC;
+ cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
+ cli->pipe_auth_flags |= AUTH_PIPE_SEAL;
+ if (cli->nt_pipe_fnum != 0)
+ cli_nt_session_close(cli);
+ }
+ }
+
+ if (cli->nt_pipe_fnum != 0)
+ cli_nt_session_close(cli);
+
+ cli->pipe_auth_flags = 0;
+
+ if (!secrets_fetch_trust_account_password(lp_workgroup(),
+ trust_password,
+ NULL, &sec_channel_type)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!cli_nt_session_open(cli, PI_NETLOGON)) {
+ DEBUG(0, ("Could not initialise %s\n",
+ get_pipe_name_from_index(PI_NETLOGON)));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ neg_flags |= NETLOGON_NEG_SCHANNEL;
+
+ result = cli_nt_setup_creds(cli, sec_channel_type, trust_password,
+ &neg_flags, 2);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ ZERO_STRUCT(cli->auth_info.sess_key);
+ cli->pipe_auth_flags = 0;
+ return result;
+ }
+
+ memcpy(cli->auth_info.sess_key, cli->sess_key,
+ sizeof(cli->auth_info.sess_key));
+
+ cli->saved_netlogon_pipe_fnum = cli->nt_pipe_fnum;
+
+ cli->pipe_auth_flags = AUTH_PIPE_NETSEC;
+ cli->pipe_auth_flags |= AUTH_PIPE_SIGN;
+ cli->pipe_auth_flags |= AUTH_PIPE_SEAL;
+
+ return NT_STATUS_OK;
+}
+
/* Built in rpcclient commands */
static struct cmd_set rpcclient_commands[] = {
@@ -331,6 +444,10 @@ static struct cmd_set rpcclient_commands[] = {
{ "list", RPC_RTYPE_NTSTATUS, cmd_listcommands, NULL, -1, "List available commands on <pipe>", "pipe" },
{ "exit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, -1, "Exit program", "" },
{ "quit", RPC_RTYPE_NTSTATUS, cmd_quit, NULL, -1, "Exit program", "" },
+ { "sign", RPC_RTYPE_NTSTATUS, cmd_sign, NULL, -1, "Force RPC pipe connections to be signed", "" },
+ { "seal", RPC_RTYPE_NTSTATUS, cmd_seal, NULL, -1, "Force RPC pipe connections to be sealed", "" },
+ { "schannel", RPC_RTYPE_NTSTATUS, cmd_schannel, NULL, -1, "Force RPC pipe connections to be sealed with 'schannel' (NETSEC). Assumes valid machine account to this domain controller.", "" },
+ { "none", RPC_RTYPE_NTSTATUS, cmd_none, NULL, -1, "Force RPC pipe connections to have no special properties", "" },
{ NULL }
};
@@ -392,8 +509,9 @@ static NTSTATUS do_cmd(struct cli_state *cli,
struct cmd_set *cmd_entry,
int argc, char **argv)
{
- NTSTATUS ntresult;
- WERROR wresult;
+ NTSTATUS ntresult;
+ WERROR wresult;
+ uchar trust_password[16];
TALLOC_CTX *mem_ctx;
@@ -401,12 +519,16 @@ static NTSTATUS do_cmd(struct cli_state *cli,
if (!(mem_ctx = talloc_init("do_cmd"))) {
DEBUG(0, ("talloc_init() failed\n"));
- return NT_STATUS_UNSUCCESSFUL;
+ return NT_STATUS_NO_MEMORY;
}
/* Open pipe */
- if (cmd_entry->pipe_idx != -1) {
+ if (cmd_entry->pipe_idx != -1
+ && cmd_entry->pipe_idx != cli->pipe_idx) {
+ if (cli->nt_pipe_fnum != 0)
+ cli_nt_session_close(cli);
+
if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) {
DEBUG(0, ("Could not initialise %s\n",
get_pipe_name_from_index(cmd_entry->pipe_idx)));
@@ -414,21 +536,25 @@ static NTSTATUS do_cmd(struct cli_state *cli,
}
}
- if (cmd_entry->pipe_idx == PI_NETLOGON) {
- uchar trust_password[16];
+ if ((cmd_entry->pipe_idx == PI_NETLOGON) && !(cli->pipe_auth_flags & AUTH_PIPE_NETSEC)) {
+ uint32 neg_flags = 0x000001ff;
uint32 sec_channel_type;
-
+
if (!secrets_fetch_trust_account_password(lp_workgroup(),
trust_password,
NULL, &sec_channel_type)) {
return NT_STATUS_UNSUCCESSFUL;
}
-
- if (!NT_STATUS_IS_OK(cli_nt_establish_netlogon(cli, sec_channel_type,
- trust_password))) {
- DEBUG(0, ("Could not initialise NETLOGON pipe\n"));
- return NT_STATUS_UNSUCCESSFUL;
+
+ ntresult = cli_nt_setup_creds(cli, sec_channel_type,
+ trust_password,
+ &neg_flags, 2);
+ if (!NT_STATUS_IS_OK(ntresult)) {
+ ZERO_STRUCT(cli->auth_info.sess_key);
+ printf("nt_setup_creds failed with %s\n", nt_errstr(ntresult));
+ return ntresult;
}
+
}
/* Run command */
@@ -450,9 +576,6 @@ static NTSTATUS do_cmd(struct cli_state *cli,
/* Cleanup */
- if (cmd_entry->pipe_idx != -1)
- cli_nt_session_close(cli);
-
talloc_destroy(mem_ctx);
return ntresult;