diff options
author | Andrew Tridgell <tridge@samba.org> | 2009-09-15 18:46:18 -0700 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2009-09-15 18:46:18 -0700 |
commit | 7744283c36803836f698c12710e8c0ec8fbd8e93 (patch) | |
tree | 62ef35c75a812c7bca36c59d3b90cd0c3095d06f /source3 | |
parent | a04caf329fefccad0fc272474025f6d23a4deaa2 (diff) | |
parent | 10e25fc5e90e9eaabedc2f3477ac1e8947c88c77 (diff) | |
download | samba-7744283c36803836f698c12710e8c0ec8fbd8e93.tar.gz samba-7744283c36803836f698c12710e8c0ec8fbd8e93.tar.bz2 samba-7744283c36803836f698c12710e8c0ec8fbd8e93.zip |
Merge branch 'master' of /home/tridge/samba/git/combined
Diffstat (limited to 'source3')
-rw-r--r-- | source3/Makefile.in | 4 | ||||
-rw-r--r-- | source3/auth/auth_netlogond.c | 26 | ||||
-rw-r--r-- | source3/include/client.h | 2 | ||||
-rw-r--r-- | source3/include/ntdomain.h | 2 | ||||
-rw-r--r-- | source3/include/proto.h | 9 | ||||
-rw-r--r-- | source3/modules/vfs_streams_xattr.c | 9 | ||||
-rw-r--r-- | source3/rpc_client/cli_pipe.c | 107 | ||||
-rw-r--r-- | source3/rpc_parse/parse_prs.c | 286 | ||||
-rw-r--r-- | source3/rpc_server/srv_netlog_nt.c | 3 | ||||
-rw-r--r-- | source3/rpc_server/srv_pipe.c | 85 |
10 files changed, 153 insertions, 380 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index a89bbae6ab..65feb8446b 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -372,7 +372,8 @@ UTIL_OBJ = ../lib/util/rbtree.o ../lib/util/signal.o ../lib/util/time.o \ CRYPTO_OBJ = ../lib/crypto/crc32.o ../lib/crypto/md5.o \ ../lib/crypto/hmacmd5.o ../lib/crypto/arcfour.o \ ../lib/crypto/md4.o \ - ../lib/crypto/sha256.o ../lib/crypto/hmacsha256.o + ../lib/crypto/sha256.o ../lib/crypto/hmacsha256.o \ + ../lib/crypto/aes.o ../lib/crypto/rijndael-alg-fst.o LIB_OBJ = $(LIBSAMBAUTIL_OBJ) $(UTIL_OBJ) $(CRYPTO_OBJ) \ lib/messages.o librpc/gen_ndr/ndr_messaging.o lib/messages_local.o \ @@ -495,6 +496,7 @@ CLDAP_OBJ = libads/cldap.o \ TLDAP_OBJ = lib/tldap.o lib/tldap_util.o lib/util_tsock.o SCHANNEL_OBJ = ../libcli/auth/credentials.o \ + ../libcli/auth/schannel_sign.o \ ../libcli/auth/schannel_state_tdb.o \ ../librpc/gen_ndr/ndr_schannel.o \ ../librpc/ndr/ndr_schannel.o \ diff --git a/source3/auth/auth_netlogond.c b/source3/auth/auth_netlogond.c index 5f4d2f16e3..8c930a552a 100644 --- a/source3/auth/auth_netlogond.c +++ b/source3/auth/auth_netlogond.c @@ -46,9 +46,21 @@ static NTSTATUS netlogond_validate(TALLOC_CTX *mem_ctx, return status; } + /* + * We have to fake a struct dcinfo, so that + * rpccli_netlogon_sam_network_logon_ex can decrypt the session keys. + */ + + p->dc = netlogon_creds_client_init_session_key(p, schannel_key); + if (p->dc == NULL) { + DEBUG(0, ("talloc failed\n")); + TALLOC_FREE(p); + return NT_STATUS_NO_MEMORY; + } + status = rpccli_schannel_bind_data(p, lp_workgroup(), DCERPC_AUTH_LEVEL_PRIVACY, - schannel_key, &auth); + p->dc, &auth); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("rpccli_schannel_bind_data failed: %s\n", nt_errstr(status))); @@ -64,18 +76,6 @@ static NTSTATUS netlogond_validate(TALLOC_CTX *mem_ctx, return status; } - /* - * We have to fake a struct dcinfo, so that - * rpccli_netlogon_sam_network_logon_ex can decrypt the session keys. - */ - - p->dc = netlogon_creds_client_init_session_key(p, schannel_key); - if (p->dc == NULL) { - DEBUG(0, ("talloc failed\n")); - TALLOC_FREE(p); - return NT_STATUS_NO_MEMORY; - } - status = rpccli_netlogon_sam_network_logon_ex( p, p, user_info->logon_parameters,/* flags such as 'allow diff --git a/source3/include/client.h b/source3/include/client.h index e83927cfe5..82d94b055f 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -55,7 +55,7 @@ struct cli_pipe_auth_data { DATA_BLOB user_session_key; union { - struct schannel_auth_struct *schannel_auth; + struct schannel_state *schannel_auth; NTLMSSP_STATE *ntlmssp_state; struct kerberos_auth_struct *kerberos_auth; } a_u; diff --git a/source3/include/ntdomain.h b/source3/include/ntdomain.h index 1d303ca64a..f90478296c 100644 --- a/source3/include/ntdomain.h +++ b/source3/include/ntdomain.h @@ -150,7 +150,7 @@ struct pipe_auth_data { enum pipe_auth_type auth_type; /* switch for union below. */ enum dcerpc_AuthLevel auth_level; union { - struct schannel_auth_struct *schannel_auth; + struct schannel_state *schannel_auth; AUTH_NTLMSSP_STATE *auth_ntlmssp_state; /* struct kerberos_auth_struct *kerberos_auth; TO BE ADDED... */ } a_u; diff --git a/source3/include/proto.h b/source3/include/proto.h index 35d1a9929d..8af6dba7b0 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -5298,7 +5298,7 @@ NTSTATUS rpccli_ntlmssp_bind_data(TALLOC_CTX *mem_ctx, struct cli_pipe_auth_data **presult); NTSTATUS rpccli_schannel_bind_data(TALLOC_CTX *mem_ctx, const char *domain, enum dcerpc_AuthLevel auth_level, - const uint8_t sess_key[16], + struct netlogon_creds_CredentialState *creds, struct cli_pipe_auth_data **presult); NTSTATUS rpccli_kerberos_bind_data(TALLOC_CTX *mem_ctx, enum dcerpc_AuthLevel auth_level, @@ -5706,13 +5706,6 @@ bool prs_uint16s(bool charmode, const char *name, prs_struct *ps, int depth, uin bool prs_uint32s(bool charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len); bool prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str); bool prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_buf_size); -void schannel_encode(struct schannel_auth_struct *a, enum dcerpc_AuthLevel auth_level, - enum schannel_direction direction, - struct NL_AUTH_SIGNATURE *verf, - char *data, size_t data_len); -bool schannel_decode(struct schannel_auth_struct *a, enum dcerpc_AuthLevel auth_level, - enum schannel_direction direction, - struct NL_AUTH_SIGNATURE *verf, char *data, size_t data_len); bool prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx); bool prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx); diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c index 033d0272c2..b68fa02a35 100644 --- a/source3/modules/vfs_streams_xattr.c +++ b/source3/modules/vfs_streams_xattr.c @@ -916,6 +916,9 @@ static ssize_t streams_xattr_pread(vfs_handle_struct *handle, NTSTATUS status; size_t length, overlap; + DEBUG(10, ("streams_xattr_pread: offset=%d, size=%d\n", + (int)offset, (int)n)); + if (sio == NULL) { return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset); } @@ -932,10 +935,12 @@ static ssize_t streams_xattr_pread(vfs_handle_struct *handle, length = ea.value.length-1; + DEBUG(10, ("streams_xattr_pread: get_ea_value returned %d bytes\n", + (int)length)); + /* Attempt to read past EOF. */ if (length <= offset) { - errno = EINVAL; - return -1; + return 0; } overlap = (offset + n) > length ? (length - offset) : n; diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index a667a9fb13..febf787815 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -21,6 +21,8 @@ #include "../libcli/auth/libcli_auth.h" #include "librpc/gen_ndr/cli_epmapper.h" #include "../librpc/gen_ndr/ndr_schannel.h" +#include "../libcli/auth/schannel.h" +#include "../libcli/auth/schannel_proto.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_CLI @@ -673,11 +675,12 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p struct NL_AUTH_SIGNATURE schannel_chk; uint32 auth_len = prhdr->auth_len; uint32 save_offset = prs_offset(current_pdu); - struct schannel_auth_struct *schannel_auth = + struct schannel_state *schannel_auth = cli->auth->a_u.schannel_auth; uint32 data_len; enum ndr_err_code ndr_err; DATA_BLOB blob; + NTSTATUS status; if (cli->auth->auth_level == DCERPC_AUTH_LEVEL_NONE || cli->auth->auth_level == DCERPC_AUTH_LEVEL_CONNECT) { @@ -720,7 +723,7 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p return NT_STATUS_BUFFER_TOO_SMALL; } - blob = data_blob_const(prs_data_p(current_pdu) + prs_offset(current_pdu), data_len); + blob = data_blob_const(prs_data_p(current_pdu) + prs_offset(current_pdu), auth_len); ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), NULL, &schannel_chk, (ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_SIGNATURE); @@ -733,21 +736,34 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, RPC_HDR *p NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &schannel_chk); } - if (!schannel_decode(schannel_auth, - cli->auth->auth_level, - SENDER_IS_ACCEPTOR, - &schannel_chk, - prs_data_p(current_pdu)+RPC_HEADER_LEN+RPC_HDR_RESP_LEN, - data_len)) { + switch (cli->auth->auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + status = schannel_unseal_packet(schannel_auth, + talloc_tos(), + (uint8_t *)prs_data_p(current_pdu)+RPC_HEADER_LEN+RPC_HDR_RESP_LEN, + data_len, + &blob); + break; + case DCERPC_AUTH_LEVEL_INTEGRITY: + status = schannel_check_packet(schannel_auth, + talloc_tos(), + (uint8_t *)prs_data_p(current_pdu)+RPC_HEADER_LEN+RPC_HDR_RESP_LEN, + data_len, + &blob); + break; + default: + status = NT_STATUS_INTERNAL_ERROR; + break; + } + + if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("cli_pipe_verify_schannel: failed to decode PDU " - "Connection to %s.\n", - rpccli_pipe_txt(debug_ctx(), cli))); + "Connection to %s (%s).\n", + rpccli_pipe_txt(debug_ctx(), cli), + nt_errstr(status))); return NT_STATUS_INVALID_PARAMETER; } - /* The sequence number gets incremented on both send and receive. */ - schannel_auth->seq_num++; - /* * Return the current pointer to the data offset. */ @@ -1915,11 +1931,12 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, { RPC_HDR_AUTH auth_info; struct NL_AUTH_SIGNATURE verf; - struct schannel_auth_struct *sas = cli->auth->a_u.schannel_auth; + struct schannel_state *sas = cli->auth->a_u.schannel_auth; char *data_p = prs_data_p(outgoing_pdu) + RPC_HEADER_LEN + RPC_HDR_RESP_LEN; size_t data_and_pad_len = prs_offset(outgoing_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN; enum ndr_err_code ndr_err; DATA_BLOB blob; + NTSTATUS status; if (!sas) { return NT_STATUS_INVALID_PARAMETER; @@ -1937,29 +1954,35 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, return NT_STATUS_NO_MEMORY; } - switch (cli->auth->auth_level) { - case DCERPC_AUTH_LEVEL_PRIVACY: - case DCERPC_AUTH_LEVEL_INTEGRITY: - DEBUG(10,("add_schannel_auth_footer: SCHANNEL seq_num=%d\n", - sas->seq_num)); + DEBUG(10,("add_schannel_auth_footer: SCHANNEL seq_num=%d\n", + sas->seq_num)); - schannel_encode(sas, - cli->auth->auth_level, - SENDER_IS_INITIATOR, - &verf, - data_p, - data_and_pad_len); - - sas->seq_num++; - break; - - default: - /* Can't happen. */ - smb_panic("bad auth level"); - /* Notreached. */ - return NT_STATUS_INVALID_PARAMETER; + switch (cli->auth->auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + status = schannel_seal_packet(sas, + talloc_tos(), + (uint8_t *)data_p, + data_and_pad_len, + &blob); + break; + case DCERPC_AUTH_LEVEL_INTEGRITY: + status = schannel_sign_packet(sas, + talloc_tos(), + (uint8_t *)data_p, + data_and_pad_len, + &blob); + break; + default: + status = NT_STATUS_INTERNAL_ERROR; + break; } + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1,("add_schannel_auth_footer: failed to process packet: %s\n", + nt_errstr(status))); + return status; + } +#if 0 ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), NULL, &verf, (ndr_push_flags_fn_t)ndr_push_NL_AUTH_SIGNATURE); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { @@ -1969,7 +1992,7 @@ static NTSTATUS add_schannel_auth_footer(struct rpc_pipe_client *cli, if (DEBUGLEVEL >= 10) { NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &verf); } - +#endif /* Finally marshall the blob. */ if (!prs_copy_data_in(outgoing_pdu, (const char *)blob.data, blob.length)) { return NT_STATUS_NO_MEMORY; @@ -3070,7 +3093,7 @@ NTSTATUS rpccli_ntlmssp_bind_data(TALLOC_CTX *mem_ctx, NTSTATUS rpccli_schannel_bind_data(TALLOC_CTX *mem_ctx, const char *domain, enum dcerpc_AuthLevel auth_level, - const uint8_t sess_key[16], + struct netlogon_creds_CredentialState *creds, struct cli_pipe_auth_data **presult) { struct cli_pipe_auth_data *result; @@ -3089,15 +3112,15 @@ NTSTATUS rpccli_schannel_bind_data(TALLOC_CTX *mem_ctx, const char *domain, goto fail; } - result->a_u.schannel_auth = talloc(result, - struct schannel_auth_struct); + result->a_u.schannel_auth = talloc(result, struct schannel_state); if (result->a_u.schannel_auth == NULL) { goto fail; } - memcpy(result->a_u.schannel_auth->sess_key, sess_key, - sizeof(result->a_u.schannel_auth->sess_key)); + result->a_u.schannel_auth->state = SCHANNEL_STATE_START; result->a_u.schannel_auth->seq_num = 0; + result->a_u.schannel_auth->initiator = true; + result->a_u.schannel_auth->creds = creds; *presult = result; return NT_STATUS_OK; @@ -3904,7 +3927,7 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli, } status = rpccli_schannel_bind_data(result, domain, auth_level, - (*pdc)->session_key, &auth); + *pdc, &auth); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("rpccli_schannel_bind_data returned %s\n", nt_errstr(status))); @@ -4122,7 +4145,7 @@ NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx, switch (cli->auth->auth_type) { case PIPE_AUTH_TYPE_SCHANNEL: *session_key = data_blob_talloc(mem_ctx, - cli->auth->a_u.schannel_auth->sess_key, 16); + cli->auth->a_u.schannel_auth->creds->session_key, 16); break; case PIPE_AUTH_TYPE_NTLMSSP: case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP: diff --git a/source3/rpc_parse/parse_prs.c b/source3/rpc_parse/parse_prs.c index 09263b45d4..edccded6c6 100644 --- a/source3/rpc_parse/parse_prs.c +++ b/source3/rpc_parse/parse_prs.c @@ -1066,292 +1066,6 @@ bool prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_ } /******************************************************************* - Create a digest over the entire packet (including the data), and - MD5 it with the session key. - ********************************************************************/ - -static void schannel_digest(struct schannel_auth_struct *a, - enum dcerpc_AuthLevel auth_level, - struct NL_AUTH_SIGNATURE *verf, - char *data, size_t data_len, - uchar digest_final[16]) -{ - uchar whole_packet_digest[16]; - uchar zeros[4]; - struct MD5Context ctx3; - uint8_t sig[8]; - - ZERO_STRUCT(zeros); - ZERO_STRUCT(sig); - - SSVAL(sig,0,verf->SignatureAlgorithm); - SSVAL(sig,2,verf->SealAlgorithm); - SSVAL(sig,4,verf->Pad); - SSVAL(sig,6,verf->Flags); - - /* 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, sig, 8); - if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { - MD5Update(&ctx3, verf->Confounder, sizeof(verf->Confounder)); - } - MD5Update(&ctx3, (const unsigned char *)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); -} - -/******************************************************************* - Calculate the key with which to encode the data payload - ********************************************************************/ - -static void schannel_get_sealing_key(struct schannel_auth_struct *a, - struct NL_AUTH_SIGNATURE *verf, - uchar sealing_key[16]) -{ - uchar zeros[4]; - uchar digest2[16]; - uchar sess_kf0[16]; - int i; - - ZERO_STRUCT(zeros); - - 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 4 zero bytes */ - 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->SequenceNumber, sizeof(verf->SequenceNumber), sealing_key); - dump_data_pw("sealing_key:\n", sealing_key, 16); -} - -/******************************************************************* - Encode or Decode the sequence number (which is symmetric) - ********************************************************************/ - -static void schannel_deal_with_seq_num(struct schannel_auth_struct *a, - struct NL_AUTH_SIGNATURE *verf) -{ - uchar zeros[4]; - uchar sequence_key[16]; - uchar digest1[16]; - - ZERO_STRUCT(zeros); - - hmac_md5(a->sess_key, zeros, sizeof(zeros), digest1); - dump_data_pw("(sequence key) digest1:\n", digest1, sizeof(digest1)); - - hmac_md5(digest1, verf->Checksum, 8, sequence_key); - - dump_data_pw("sequence_key:\n", sequence_key, sizeof(sequence_key)); - - dump_data_pw("seq_num (before):\n", verf->SequenceNumber, sizeof(verf->SequenceNumber)); - arcfour_crypt(verf->SequenceNumber, sequence_key, 8); - dump_data_pw("seq_num (after):\n", verf->SequenceNumber, sizeof(verf->SequenceNumber)); -} - -/******************************************************************* - Encode a blob of data using the 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 schannel_encode(struct schannel_auth_struct *a, enum dcerpc_AuthLevel auth_level, - enum schannel_direction direction, - struct NL_AUTH_SIGNATURE *verf, - char *data, size_t data_len) -{ - uchar digest_final[16]; - uchar confounder[8]; - uchar seq_num[8]; - static const uchar nullbytes[8] = { 0, }; - - DEBUG(10,("SCHANNEL: schannel_encode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len)); - - /* fill the 'confounder' with random data */ - generate_random_buffer(confounder, sizeof(confounder)); - - dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key)); - - 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; - } - - dump_data_pw("verf->SequenceNumber:\n", verf->SequenceNumber, sizeof(verf->SequenceNumber)); - - if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { - verf->SealAlgorithm = NL_SEAL_RC4; - } else { - verf->SealAlgorithm = NL_SEAL_NONE; - } - - verf->SignatureAlgorithm = NL_SIGN_HMAC_MD5; - verf->Pad = 0xffff; - verf->Flags = 0x0000; - - memcpy(verf->SequenceNumber, seq_num, sizeof(verf->SequenceNumber)); - memcpy(verf->Checksum, nullbytes, sizeof(verf->Checksum)); - memcpy(verf->Confounder, confounder, sizeof(verf->Confounder)); - - /* produce a digest of the packet to prove it's legit (before we seal it) */ - schannel_digest(a, auth_level, verf, data, data_len, digest_final); - memcpy(verf->Checksum, digest_final, sizeof(verf->Checksum)); - - if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { - uchar sealing_key[16]; - - /* get the key to encode the data with */ - schannel_get_sealing_key(a, verf, sealing_key); - - /* encode the verification data */ - dump_data_pw("verf->Confounder:\n", verf->Confounder, sizeof(verf->Confounder)); - arcfour_crypt(verf->Confounder, sealing_key, 8); - - dump_data_pw("verf->Confounder_enc:\n", verf->Confounder, sizeof(verf->Confounder)); - - /* encode the packet payload */ - dump_data_pw("data:\n", (const unsigned char *)data, data_len); - arcfour_crypt((unsigned char *)data, sealing_key, data_len); - dump_data_pw("data_enc:\n", (const unsigned char *)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... */ - schannel_deal_with_seq_num(a, verf); - - return; -} - -/******************************************************************* - Decode a blob of data using the schannel alogrithm, also verifiying - a checksum over the original data. We currently can verify signed messages, - as well as decode sealed messages - ********************************************************************/ - -bool schannel_decode(struct schannel_auth_struct *a, enum dcerpc_AuthLevel auth_level, - enum schannel_direction direction, - struct NL_AUTH_SIGNATURE *verf, char *data, size_t data_len) -{ - uchar digest_final[16]; - - static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE; - static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE; - const uchar *schannel_sig = NULL; - - uchar seq_num[8]; - - DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len)); - - if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { - schannel_sig = schannel_seal_sig; - } else { - schannel_sig = schannel_sign_sig; - } - - /* Create the expected sequence number for comparison */ - 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: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len)); - dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key)); - - dump_data_pw("seq_num:\n", seq_num, sizeof(seq_num)); - - /* 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... */ - schannel_deal_with_seq_num(a, verf); - - if (memcmp(verf->SequenceNumber, 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 - */ - DEBUG(2, ("schannel_decode: FAILED: packet sequence number:\n")); - dump_data(2, verf->SequenceNumber, sizeof(verf->SequenceNumber)); - DEBUG(2, ("should be:\n")); - dump_data(2, seq_num, sizeof(seq_num)); - - return False; - } - - if (memcmp(&verf->SignatureAlgorithm, &schannel_sig[0], 2) || - memcmp(&verf->SealAlgorithm, &schannel_sig[2], 2) || - memcmp(&verf->Pad, &schannel_sig[4], 2) || - memcmp(&verf->Flags, &schannel_sig[6], 2)) { - /* Validate that the other end sent the expected header */ - DEBUG(2, ("schannel_decode: FAILED: packet header:\n")); - dump_data(2, (const uint8_t *)verf, sizeof(schannel_sig)); - DEBUG(2, ("should be:\n")); - dump_data(2, schannel_sig, sizeof(schannel_sig)); - return False; - } - - if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { - uchar sealing_key[16]; - - /* get the key to extract the data with */ - schannel_get_sealing_key(a, verf, sealing_key); - - /* extract the verification data */ - dump_data_pw("verf->Confounder:\n", verf->Confounder, - sizeof(verf->Confounder)); - arcfour_crypt(verf->Confounder, sealing_key, 8); - - dump_data_pw("verf->Confounder_dec:\n", verf->Confounder, - sizeof(verf->Confounder)); - - /* extract the packet payload */ - dump_data_pw("data :\n", (const unsigned char *)data, data_len); - arcfour_crypt((unsigned char *)data, sealing_key, data_len); - dump_data_pw("datadec:\n", (const unsigned char *)data, data_len); - } - - /* digest includes 'data' after unsealing */ - schannel_digest(a, auth_level, verf, data, data_len, digest_final); - - dump_data_pw("Calculated digest:\n", digest_final, - sizeof(digest_final)); - dump_data_pw("verf->Checksum:\n", verf->Checksum, - sizeof(verf->Checksum)); - - /* compare - if the client got the same result as us, then - it must know the session key */ - return (memcmp(digest_final, verf->Checksum, - sizeof(verf->Checksum)) == 0); -} - -/******************************************************************* creates a new prs_struct containing a DATA_BLOB ********************************************************************/ bool prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx) diff --git a/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c index 06d4937261..33a81fa651 100644 --- a/source3/rpc_server/srv_netlog_nt.c +++ b/source3/rpc_server/srv_netlog_nt.c @@ -27,6 +27,7 @@ #include "includes.h" #include "../libcli/auth/libcli_auth.h" #include "../libcli/auth/schannel_state.h" +#include "../libcli/auth/schannel.h" extern userdom_struct current_user_info; @@ -1053,7 +1054,7 @@ static NTSTATUS _netr_LogonSamLogon_base(pipes_struct *p, || (p->auth.a_u.schannel_auth == NULL)) { return NT_STATUS_INVALID_HANDLE; } - memcpy(pipe_session_key, p->auth.a_u.schannel_auth->sess_key, 16); + memcpy(pipe_session_key, p->auth.a_u.schannel_auth->creds->session_key, 16); } switch (r->in.validation_level) { diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index 3bd68c4e72..576bd85745 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -30,6 +30,8 @@ #include "includes.h" #include "../libcli/auth/libcli_auth.h" #include "../librpc/gen_ndr/ndr_schannel.h" +#include "../libcli/auth/schannel.h" +#include "../libcli/auth/schannel_proto.h" extern struct current_user current_user; @@ -285,6 +287,7 @@ static bool create_next_pdu_schannel(pipes_struct *p) uint32 data_space_available; uint32 data_len_left; uint32 data_pos; + NTSTATUS status; /* * If we're in the fault state, keep returning fault PDU's until @@ -426,13 +429,36 @@ static bool create_next_pdu_schannel(pipes_struct *p) return False; } - schannel_encode(p->auth.a_u.schannel_auth, - p->auth.auth_level, SENDER_IS_ACCEPTOR, &verf, - prs_data_p(&p->out_data.frag) + data_pos, - data_len + ss_padding_len); + switch (p->auth.auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + status = schannel_seal_packet(p->auth.a_u.schannel_auth, + talloc_tos(), + (uint8_t *)prs_data_p(&p->out_data.frag) + data_pos, + data_len + ss_padding_len, + &blob); + break; + case DCERPC_AUTH_LEVEL_INTEGRITY: + status = schannel_sign_packet(p->auth.a_u.schannel_auth, + talloc_tos(), + (uint8_t *)prs_data_p(&p->out_data.frag) + data_pos, + data_len + ss_padding_len, + &blob); + break; + default: + status = NT_STATUS_INTERNAL_ERROR; + break; + } + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("create_next_pdu_schannel: failed to process packet: %s\n", + nt_errstr(status))); + prs_mem_free(&p->out_data.frag); + return false; + } /* Finally marshall the blob. */ +#if 0 ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), NULL, &verf, (ndr_push_flags_fn_t)ndr_push_NL_AUTH_SIGNATURE); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { @@ -443,13 +469,11 @@ static bool create_next_pdu_schannel(pipes_struct *p) if (DEBUGLEVEL >= 10) { NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &verf); } - +#endif if (!prs_copy_data_in(&p->out_data.frag, (const char *)blob.data, blob.length)) { prs_mem_free(&p->out_data.frag); return false; } - - p->auth.a_u.schannel_auth->seq_num++; } /* @@ -1376,7 +1400,7 @@ static bool pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p, */ become_root(); - status = schannel_fetch_session_key(p->mem_ctx, + status = schannel_fetch_session_key(p, neg.oem_netbios_computer.a, &creds); unbecome_root(); @@ -1386,19 +1410,16 @@ static bool pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p, return False; } - p->auth.a_u.schannel_auth = talloc(p, struct schannel_auth_struct); + p->auth.a_u.schannel_auth = talloc(p, struct schannel_state); if (!p->auth.a_u.schannel_auth) { TALLOC_FREE(creds); return False; } - memset(p->auth.a_u.schannel_auth->sess_key, 0, sizeof(p->auth.a_u.schannel_auth->sess_key)); - memcpy(p->auth.a_u.schannel_auth->sess_key, creds->session_key, - sizeof(creds->session_key)); - - TALLOC_FREE(creds); - + p->auth.a_u.schannel_auth->state = SCHANNEL_STATE_START; p->auth.a_u.schannel_auth->seq_num = 0; + p->auth.a_u.schannel_auth->initiator = false; + p->auth.a_u.schannel_auth->creds = creds; /* * JRA. Should we also copy the schannel session key into the pipe session key p->session_key @@ -2152,6 +2173,7 @@ bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss struct NL_AUTH_SIGNATURE schannel_chk; enum ndr_err_code ndr_err; DATA_BLOB blob; + NTSTATUS status; auth_len = p->hdr.auth_len; @@ -2213,13 +2235,29 @@ bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &schannel_chk); } - if (!schannel_decode(p->auth.a_u.schannel_auth, - p->auth.auth_level, - SENDER_IS_INITIATOR, - &schannel_chk, - prs_data_p(rpc_in)+RPC_HDR_REQ_LEN, data_len)) { - DEBUG(3,("failed to decode PDU\n")); - return False; + switch (auth_info.auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + status = schannel_unseal_packet(p->auth.a_u.schannel_auth, + talloc_tos(), + (uint8_t *)prs_data_p(rpc_in)+RPC_HDR_REQ_LEN, + data_len, + &blob); + break; + case DCERPC_AUTH_LEVEL_INTEGRITY: + status = schannel_check_packet(p->auth.a_u.schannel_auth, + talloc_tos(), + (uint8_t *)prs_data_p(rpc_in)+RPC_HDR_REQ_LEN, + data_len, + &blob); + break; + default: + status = NT_STATUS_INTERNAL_ERROR; + break; + } + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("failed to unseal packet: %s\n", nt_errstr(status))); + return false; } /* @@ -2232,9 +2270,6 @@ bool api_pipe_schannel_process(pipes_struct *p, prs_struct *rpc_in, uint32 *p_ss return False; } - /* The sequence number gets incremented on both send and receive. */ - p->auth.a_u.schannel_auth->seq_num++; - /* * Remember the padding length. We must remove it from the real data * stream once the sign/seal is done. |