diff options
-rw-r--r-- | source3/include/client.h | 15 | ||||
-rw-r--r-- | source3/include/ntlmssp.h | 5 | ||||
-rw-r--r-- | source3/include/rpc_dce.h | 26 | ||||
-rw-r--r-- | source3/lib/util.c | 11 | ||||
-rw-r--r-- | source3/libsmb/cliconnect.c | 6 | ||||
-rw-r--r-- | source3/libsmb/clientgen.c | 42 | ||||
-rw-r--r-- | source3/libsmb/ntlmssp.c | 107 | ||||
-rw-r--r-- | source3/libsmb/ntlmssp_parse.c | 75 | ||||
-rw-r--r-- | source3/libsmb/ntlmssp_sign.c | 206 | ||||
-rw-r--r-- | source3/libsmb/pwd_cache.c | 14 | ||||
-rw-r--r-- | source3/libsmb/smbencrypt.c | 31 | ||||
-rw-r--r-- | source3/rpc_client/cli_pipe.c | 1057 | ||||
-rw-r--r-- | source3/rpc_parse/parse_prs.c | 270 | ||||
-rw-r--r-- | source3/rpc_parse/parse_rpc.c | 26 | ||||
-rw-r--r-- | source3/rpc_server/srv_pipe.c | 40 | ||||
-rw-r--r-- | source3/rpcclient/rpcclient.c | 153 |
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, ¤t_offset)) + if (!rpc_read(cli, rdata, len, ¤t_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; |