diff options
author | Alexander Bokovoy <ab@samba.org> | 2012-03-02 16:18:16 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2012-03-13 12:23:44 +0100 |
commit | 7d4ed899831a853ec2eef8dcd82d74fdbf568f0e (patch) | |
tree | 4ff03d559933f3b11ae4c96a3ad357ff4abcda89 /source3 | |
parent | e25f830f1df323607999179e00a5a39197bf02ea (diff) | |
download | samba-7d4ed899831a853ec2eef8dcd82d74fdbf568f0e.tar.gz samba-7d4ed899831a853ec2eef8dcd82d74fdbf568f0e.tar.bz2 samba-7d4ed899831a853ec2eef8dcd82d74fdbf568f0e.zip |
s3-rpc: Decrypt with the proper session key in CreateTrustedDomainEx2.
On LSA and SAMR pipes session_key is truncated to 16 byte when doing encryption/decryption.
However, this was not done for trusted domain-related modifying operations.
As result, Samba 4 client libraries do not work against Samba 3 while working
against Windows 2008 r2.
Solved this by introducing "session_extract_session_key()" function that allows to specify
intent of use of the key.
Signed-off-by: Andreas Schneider <asn@samba.org>
Autobuild-User: Andreas Schneider <asn@cryptomilk.org>
Autobuild-Date: Tue Mar 13 12:23:44 CET 2012 on sn-devel-104
Diffstat (limited to 'source3')
-rw-r--r-- | source3/auth/auth_util.c | 28 | ||||
-rw-r--r-- | source3/auth/proto.h | 1 | ||||
-rw-r--r-- | source3/include/auth.h | 6 | ||||
-rw-r--r-- | source3/rpc_server/lsa/srv_lsa_nt.c | 127 | ||||
-rw-r--r-- | source3/rpc_server/samr/srv_samr_nt.c | 37 |
5 files changed, 120 insertions, 79 deletions
diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index 21a8642751..4f6ebfa4a4 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -1618,3 +1618,31 @@ NTSTATUS do_map_to_guest_server_info(NTSTATUS status, return status; } + +/* + Extract session key from a session info and return it in a blob + if intent is KEY_USE_16BYTES, truncate it to 16 bytes + + See sections 3.2.4.15 and 3.3.4.2 of MS-SMB + Also see https://lists.samba.org/archive/cifs-protocol/2012-January/002265.html for details + + Note that returned session_key is referencing the original key, it is supposed to be + short-lived. If original session_info->session_key is gone, the reference will be broken. +*/ +NTSTATUS session_extract_session_key(const struct auth_session_info *session_info, DATA_BLOB *session_key, enum session_key_use_intent intent) +{ + + if (session_key == NULL || session_info == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (session_info->session_key.length == 0) { + return NT_STATUS_NO_USER_SESSION_KEY; + } + + *session_key = session_info->session_key; + if (intent == KEY_USE_16BYTES) { + session_key->length = MIN(session_info->session_key.length, 16); + } + return NT_STATUS_OK; +} diff --git a/source3/auth/proto.h b/source3/auth/proto.h index 01e2934dc7..44ae9097a5 100644 --- a/source3/auth/proto.h +++ b/source3/auth/proto.h @@ -248,6 +248,7 @@ NTSTATUS make_server_info_wbcAuthUserInfo(TALLOC_CTX *mem_ctx, struct auth_serversupplied_info **server_info); void free_user_info(struct auth_usersupplied_info **user_info); bool is_trusted_domain(const char* dom_name); +NTSTATUS session_extract_session_key(const struct auth_session_info *session_info, DATA_BLOB *session_key, enum session_key_use_intent intent); /* The following definitions come from auth/user_info.c */ diff --git a/source3/include/auth.h b/source3/include/auth.h index 7f2c3e5db7..693a0df383 100644 --- a/source3/include/auth.h +++ b/source3/include/auth.h @@ -128,6 +128,12 @@ struct auth_init_function_entry { extern const struct gensec_security_ops gensec_ntlmssp3_server_ops; +/* Intent of use for session key. LSA and SAMR pipes use 16 bytes of session key when doing create/modify calls */ +enum session_key_use_intent { + KEY_USE_FULL = 0, + KEY_USE_16BYTES +}; + /* Changed from 1 -> 2 to add the logon_parameters field. */ /* Changed from 2 -> 3 when we reworked many auth structures to use IDL or be in common with Samba4 */ #define AUTH_INTERFACE_VERSION 3 diff --git a/source3/rpc_server/lsa/srv_lsa_nt.c b/source3/rpc_server/lsa/srv_lsa_nt.c index 0a5cda503d..48bdfdb8ad 100644 --- a/source3/rpc_server/lsa/srv_lsa_nt.c +++ b/source3/rpc_server/lsa/srv_lsa_nt.c @@ -287,7 +287,7 @@ static NTSTATUS lookup_lsa_sids(TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } - DEBUG(5, ("init_lsa_sids: looking up name %s\n", full_name)); + DEBUG(5, ("lookup_lsa_sids: looking up name %s\n", full_name)); if (!lookup_name(mem_ctx, full_name, flags, &domain, NULL, &sid, &type)) { @@ -300,12 +300,12 @@ static NTSTATUS lookup_lsa_sids(TALLOC_CTX *mem_ctx, case SID_NAME_DOMAIN: case SID_NAME_ALIAS: case SID_NAME_WKN_GRP: - DEBUG(5, ("init_lsa_sids: %s found\n", full_name)); + DEBUG(5, ("lookup_lsa_sids: %s found\n", full_name)); /* Leave these unchanged */ break; default: /* Don't hand out anything but the list above */ - DEBUG(5, ("init_lsa_sids: %s not found\n", full_name)); + DEBUG(5, ("lookup_lsa_sids: %s not found\n", full_name)); type = SID_NAME_UNKNOWN; break; } @@ -1309,10 +1309,7 @@ NTSTATUS _lsa_LookupNames3(struct pipes_struct *p, DEBUG(5,("_lsa_LookupNames3: truncating name lookup list to %d\n", num_entries)); } - /* Probably the lookup_level is some sort of bitmask. */ - if (r->in.level == 1) { - flags = LOOKUP_NAME_ALL; - } + flags = lsa_lookup_level_to_flags(r->in.level); domains = talloc_zero(p->mem_ctx, struct lsa_RefDomainList); if (!domains) { @@ -1660,6 +1657,46 @@ NTSTATUS _lsa_OpenTrustedDomainByName(struct pipes_struct *p, r->out.trustdom_handle); } +static NTSTATUS get_trustdom_auth_blob(struct pipes_struct *p, + TALLOC_CTX *mem_ctx, DATA_BLOB *auth_blob, + struct trustDomainPasswords *auth_struct) +{ + enum ndr_err_code ndr_err; + DATA_BLOB lsession_key; + NTSTATUS status; + + status = session_extract_session_key(p->session_info, &lsession_key, KEY_USE_16BYTES); + if (!NT_STATUS_IS_OK(status)) { + return NT_STATUS_INVALID_PARAMETER; + } + + arcfour_crypt_blob(auth_blob->data, auth_blob->length, &lsession_key); + ndr_err = ndr_pull_struct_blob(auth_blob, mem_ctx, + auth_struct, + (ndr_pull_flags_fn_t)ndr_pull_trustDomainPasswords); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return NT_STATUS_INVALID_PARAMETER; + } + + return NT_STATUS_OK; +} + +static NTSTATUS get_trustauth_inout_blob(TALLOC_CTX *mem_ctx, + struct trustAuthInOutBlob *iopw, + DATA_BLOB *trustauth_blob) +{ + enum ndr_err_code ndr_err; + + ndr_err = ndr_push_struct_blob(trustauth_blob, mem_ctx, + iopw, + (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return NT_STATUS_INVALID_PARAMETER; + } + + return NT_STATUS_OK; +} + /*************************************************************************** _lsa_CreateTrustedDomainEx2 ***************************************************************************/ @@ -1674,7 +1711,6 @@ NTSTATUS _lsa_CreateTrustedDomainEx2(struct pipes_struct *p, size_t sd_size; struct pdb_trusted_domain td; struct trustDomainPasswords auth_struct; - enum ndr_err_code ndr_err; DATA_BLOB auth_blob; if (!IS_DC) { @@ -1738,27 +1774,18 @@ NTSTATUS _lsa_CreateTrustedDomainEx2(struct pipes_struct *p, auth_blob.length = r->in.auth_info_internal->auth_blob.size; auth_blob.data = r->in.auth_info_internal->auth_blob.data; - arcfour_crypt_blob(auth_blob.data, auth_blob.length, - &p->session_info->session_key); - - ndr_err = ndr_pull_struct_blob(&auth_blob, p->mem_ctx, - &auth_struct, - (ndr_pull_flags_fn_t) ndr_pull_trustDomainPasswords); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + status = get_trustdom_auth_blob(p, p->mem_ctx, &auth_blob, &auth_struct); + if (!NT_STATUS_IS_OK(status)) { return NT_STATUS_UNSUCCESSFUL; } - ndr_err = ndr_push_struct_blob(&td.trust_auth_incoming, p->mem_ctx, - &auth_struct.incoming, - (ndr_push_flags_fn_t) ndr_push_trustAuthInOutBlob); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + status = get_trustauth_inout_blob(p->mem_ctx, &auth_struct.incoming, &td.trust_auth_incoming); + if (!NT_STATUS_IS_OK(status)) { return NT_STATUS_UNSUCCESSFUL; } - ndr_err = ndr_push_struct_blob(&td.trust_auth_outgoing, p->mem_ctx, - &auth_struct.outgoing, - (ndr_push_flags_fn_t) ndr_push_trustAuthInOutBlob); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + status = get_trustauth_inout_blob(p->mem_ctx, &auth_struct.outgoing, &td.trust_auth_outgoing); + if (!NT_STATUS_IS_OK(status)) { return NT_STATUS_UNSUCCESSFUL; } } else { @@ -2244,6 +2271,7 @@ NTSTATUS _lsa_SetSecret(struct pipes_struct *p, DATA_BLOB cleartext_blob_old = data_blob_null; DATA_BLOB *cleartext_blob_new_p = NULL; DATA_BLOB *cleartext_blob_old_p = NULL; + DATA_BLOB session_key; if (!find_policy_by_hnd(p, r->in.sec_handle, (void **)(void *)&info)) { return NT_STATUS_INVALID_HANDLE; @@ -2257,12 +2285,17 @@ NTSTATUS _lsa_SetSecret(struct pipes_struct *p, return NT_STATUS_ACCESS_DENIED; } + status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); + if(!NT_STATUS_IS_OK(status)) { + return status; + } + if (r->in.new_val) { blob_new = data_blob_const(r->in.new_val->data, r->in.new_val->length); status = sess_decrypt_blob(p->mem_ctx, &blob_new, - &p->session_info->session_key, + &session_key, &cleartext_blob_new); if (!NT_STATUS_IS_OK(status)) { return status; @@ -2276,7 +2309,7 @@ NTSTATUS _lsa_SetSecret(struct pipes_struct *p, r->in.old_val->length); status = sess_decrypt_blob(p->mem_ctx, &blob_old, - &p->session_info->session_key, + &session_key, &cleartext_blob_old); if (!NT_STATUS_IS_OK(status)) { return status; @@ -2310,6 +2343,7 @@ NTSTATUS _lsa_QuerySecret(struct pipes_struct *p, struct lsa_info *info = NULL; DATA_BLOB blob_new, blob_old; DATA_BLOB blob_new_crypt, blob_old_crypt; + DATA_BLOB session_key; NTTIME nttime_new, nttime_old; NTSTATUS status; @@ -2333,6 +2367,11 @@ NTSTATUS _lsa_QuerySecret(struct pipes_struct *p, return status; } + status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); + if(!NT_STATUS_IS_OK(status)) { + return status; + } + if (r->in.new_val) { if (blob_new.length) { if (!r->out.new_val->buf) { @@ -2343,7 +2382,7 @@ NTSTATUS _lsa_QuerySecret(struct pipes_struct *p, } blob_new_crypt = sess_encrypt_blob(p->mem_ctx, &blob_new, - &p->session_info->session_key); + &session_key); if (!blob_new_crypt.length) { return NT_STATUS_NO_MEMORY; } @@ -2364,7 +2403,7 @@ NTSTATUS _lsa_QuerySecret(struct pipes_struct *p, } blob_old_crypt = sess_encrypt_blob(p->mem_ctx, &blob_old, - &p->session_info->session_key); + &session_key); if (!blob_old_crypt.length) { return NT_STATUS_NO_MEMORY; } @@ -3468,40 +3507,6 @@ static NTSTATUS info_ex_2_pdb_trusted_domain( return NT_STATUS_OK; } -static NTSTATUS get_trustdom_auth_blob(struct pipes_struct *p, - TALLOC_CTX *mem_ctx, DATA_BLOB *auth_blob, - struct trustDomainPasswords *auth_struct) -{ - enum ndr_err_code ndr_err; - - arcfour_crypt_blob(auth_blob->data, auth_blob->length, - &p->session_info->session_key); - ndr_err = ndr_pull_struct_blob(auth_blob, mem_ctx, - auth_struct, - (ndr_pull_flags_fn_t)ndr_pull_trustDomainPasswords); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return NT_STATUS_INVALID_PARAMETER; - } - - return NT_STATUS_OK; -} - -static NTSTATUS get_trustauth_inout_blob(TALLOC_CTX *mem_ctx, - struct trustAuthInOutBlob *iopw, - DATA_BLOB *trustauth_blob) -{ - enum ndr_err_code ndr_err; - - ndr_err = ndr_push_struct_blob(trustauth_blob, mem_ctx, - iopw, - (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return NT_STATUS_INVALID_PARAMETER; - } - - return NT_STATUS_OK; -} - static NTSTATUS setInfoTrustedDomain_base(struct pipes_struct *p, TALLOC_CTX *mem_ctx, struct lsa_info *policy, diff --git a/source3/rpc_server/samr/srv_samr_nt.c b/source3/rpc_server/samr/srv_samr_nt.c index ebe6e451d4..77888ea1e8 100644 --- a/source3/rpc_server/samr/srv_samr_nt.c +++ b/source3/rpc_server/samr/srv_samr_nt.c @@ -5036,6 +5036,7 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, uint32_t fields = 0; bool ret; char *rhost; + DATA_BLOB session_key; DEBUG(5,("_samr_SetUserInfo: %d\n", __LINE__)); @@ -5193,10 +5194,14 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, break; case 18: + status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); + if(!NT_STATUS_IS_OK(status)) { + return status; + } /* Used by AS/U JRA. */ status = set_user_info_18(&info->info18, p->mem_ctx, - &p->session_info->session_key, + &session_key, pwd); break; @@ -5206,18 +5211,20 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, break; case 21: + status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); + if(!NT_STATUS_IS_OK(status)) { + return status; + } status = set_user_info_21(&info->info21, p->mem_ctx, - &p->session_info->session_key, + &session_key, pwd); break; case 23: - if (!p->session_info->session_key.length) { - status = NT_STATUS_NO_USER_SESSION_KEY; - } + status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); arcfour_crypt_blob(info->info23.password.data, 516, - &p->session_info->session_key); + &session_key); dump_data(100, info->info23.password.data, 516); @@ -5228,12 +5235,10 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, break; case 24: - if (!p->session_info->session_key.length) { - status = NT_STATUS_NO_USER_SESSION_KEY; - } + status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); arcfour_crypt_blob(info->info24.password.data, 516, - &p->session_info->session_key); + &session_key); dump_data(100, info->info24.password.data, 516); @@ -5243,12 +5248,10 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, break; case 25: - if (!p->session_info->session_key.length) { - status = NT_STATUS_NO_USER_SESSION_KEY; - } + status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); encode_or_decode_arc4_passwd_buffer( info->info25.password.data, - &p->session_info->session_key); + &session_key); dump_data(100, info->info25.password.data, 532); @@ -5258,12 +5261,10 @@ NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, break; case 26: - if (!p->session_info->session_key.length) { - status = NT_STATUS_NO_USER_SESSION_KEY; - } + status = session_extract_session_key(p->session_info, &session_key, KEY_USE_16BYTES); encode_or_decode_arc4_passwd_buffer( info->info26.password.data, - &p->session_info->session_key); + &session_key); dump_data(100, info->info26.password.data, 516); |