diff options
Diffstat (limited to 'source4/auth')
-rw-r--r-- | source4/auth/auth_sam_reply.c | 109 | ||||
-rw-r--r-- | source4/auth/config.mk | 1 | ||||
-rw-r--r-- | source4/auth/gensec/config.mk | 4 | ||||
-rw-r--r-- | source4/auth/gensec/gensec_krb5.c | 6 | ||||
-rw-r--r-- | source4/auth/kerberos/config.mk | 1 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos.h | 7 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_pac.c | 182 | ||||
-rw-r--r-- | source4/auth/kerberos/kerberos_verify.c | 17 |
8 files changed, 299 insertions, 28 deletions
diff --git a/source4/auth/auth_sam_reply.c b/source4/auth/auth_sam_reply.c new file mode 100644 index 0000000000..2ff071f737 --- /dev/null +++ b/source4/auth/auth_sam_reply.c @@ -0,0 +1,109 @@ +/* + Unix SMB/CIFS implementation. + + Convert a server info struct into the form for PAC and NETLOGON replies + + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004 + Copyright (C) Stefan Metzmacher <metze@samba.org> 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "rpc_server/dcerpc_server.h" +#include "rpc_server/common/common.h" +#include "librpc/gen_ndr/ndr_dcom.h" +#include "auth/auth.h" +#include "lib/ldb/include/ldb.h" + +NTSTATUS auth_convert_server_info_sambaseinfo(TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *server_info, + struct netr_SamBaseInfo **_sam) +{ + struct netr_SamBaseInfo *sam = talloc_zero(mem_ctx, struct netr_SamBaseInfo); + NT_STATUS_HAVE_NO_MEMORY(sam); + + sam->last_logon = server_info->last_logon; + sam->last_logoff = server_info->last_logoff; + sam->acct_expiry = server_info->acct_expiry; + sam->last_password_change = server_info->last_password_change; + sam->allow_password_change = server_info->allow_password_change; + sam->force_password_change = server_info->force_password_change; + + sam->account_name.string = server_info->account_name; + sam->full_name.string = server_info->full_name; + sam->logon_script.string = server_info->logon_script; + sam->profile_path.string = server_info->profile_path; + sam->home_directory.string = server_info->home_directory; + sam->home_drive.string = server_info->home_drive; + + sam->logon_count = server_info->logon_count; + sam->bad_password_count = sam->bad_password_count; + sam->rid = server_info->account_sid->sub_auths[server_info->account_sid->num_auths-1]; + sam->primary_gid = server_info->primary_group_sid->sub_auths[server_info->primary_group_sid->num_auths-1]; + + sam->groups.count = 0; + sam->groups.rids = NULL; + + if (server_info->n_domain_groups > 0) { + int i; + sam->groups.rids = talloc_array(sam, struct samr_RidWithAttribute, + server_info->n_domain_groups); + + if (sam->groups.rids == NULL) + return NT_STATUS_NO_MEMORY; + + for (i=0; i<server_info->n_domain_groups; i++) { + + struct dom_sid *group_sid = server_info->domain_groups[i]; + sam->groups.rids[sam->groups.count].rid = + group_sid->sub_auths[group_sid->num_auths-1]; + + sam->groups.rids[sam->groups.count].attributes = + SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; + sam->groups.count += 1; + } + } + + sam->user_flags = 0; /* TODO: w2k3 uses 0x120. We know 0x20 + * as extra sids (PAC doc) but what is + * 0x100? */ + sam->acct_flags = server_info->acct_flags; + sam->logon_server.string = lp_netbios_name(); + sam->domain.string = server_info->domain_name; + + sam->domain_sid = dom_sid_dup(mem_ctx, server_info->account_sid); + NT_STATUS_HAVE_NO_MEMORY(sam->domain_sid); + sam->domain_sid->num_auths--; + + ZERO_STRUCT(sam->unknown); + + ZERO_STRUCT(sam->key); + if (server_info->user_session_key.length == sizeof(sam->key.key)) { + memcpy(sam->key.key, server_info->user_session_key.data, sizeof(sam->key.key)); + } + + ZERO_STRUCT(sam->LMSessKey); + if (server_info->lm_session_key.length == sizeof(sam->LMSessKey.key)) { + memcpy(sam->LMSessKey.key, server_info->lm_session_key.data, + sizeof(sam->LMSessKey.key)); + } + + *_sam = sam; + + return NT_STATUS_OK; +} + diff --git a/source4/auth/config.mk b/source4/auth/config.mk index 37c6ddc931..405f776830 100644 --- a/source4/auth/config.mk +++ b/source4/auth/config.mk @@ -76,6 +76,7 @@ INIT_OBJ_FILES = \ auth/auth.o ADD_OBJ_FILES = \ auth/auth_util.o \ + auth/auth_sam_reply.o \ auth/ntlm_check.o # End SUBSYSTEM AUTH ####################### diff --git a/source4/auth/gensec/config.mk b/source4/auth/gensec/config.mk index 34587e2e45..03f7f24848 100644 --- a/source4/auth/gensec/config.mk +++ b/source4/auth/gensec/config.mk @@ -14,7 +14,7 @@ REQUIRED_SUBSYSTEMS = \ SUBSYSTEM = GENSEC INIT_FUNCTION = gensec_krb5_init INIT_OBJ_FILES = auth/gensec/gensec_krb5.o -REQUIRED_SUBSYSTEMS = NDR_KRB5PAC KERBEROS KERBEROS_LIB AUTH +REQUIRED_SUBSYSTEMS = KERBEROS AUTH # End MODULE gensec_krb5 ################################################ @@ -24,7 +24,7 @@ REQUIRED_SUBSYSTEMS = NDR_KRB5PAC KERBEROS KERBEROS_LIB AUTH SUBSYSTEM = GENSEC INIT_FUNCTION = gensec_gssapi_init INIT_OBJ_FILES = auth/gensec/gensec_gssapi.o -REQUIRED_SUBSYSTEMS = KERBEROS_LIB AUTH +REQUIRED_SUBSYSTEMS = KERBEROS AUTH # End MODULE gensec_gssapi ################################################ diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c index c8367d33f7..bd705531bd 100644 --- a/source4/auth/gensec/gensec_krb5.c +++ b/source4/auth/gensec/gensec_krb5.c @@ -47,7 +47,7 @@ struct gensec_krb5_state { krb5_auth_context auth_context; krb5_ccache ccache; krb5_data ticket; - krb5_keyblock keyblock; + krb5_keyblock *keyblock; char *peer_principal; }; @@ -61,8 +61,8 @@ static int gensec_krb5_destory(void *ptr) } /* ccache freed in a child destructor */ - krb5_free_keyblock_contents(gensec_krb5_state->smb_krb5_context->krb5_context, - &gensec_krb5_state->keyblock); + krb5_free_keyblock(gensec_krb5_state->smb_krb5_context->krb5_context, + &gensec_krb5_state->keyblock); if (gensec_krb5_state->auth_context) { krb5_auth_con_free(gensec_krb5_state->smb_krb5_context->krb5_context, diff --git a/source4/auth/kerberos/config.mk b/source4/auth/kerberos/config.mk index 62710f3cc4..56ce64fdb1 100644 --- a/source4/auth/kerberos/config.mk +++ b/source4/auth/kerberos/config.mk @@ -8,5 +8,6 @@ ADD_OBJ_FILES = \ auth/kerberos/kerberos_util.o \ auth/kerberos/kerberos_pac.o \ auth/kerberos/gssapi_parse.o +REQUIRED_SUBSYSTEMS = KERBEROS_LIB NDR_KRB5PAC # End SUBSYSTEM KERBEROS ################################# diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h index ca0bbbed0e..1fd48197f8 100644 --- a/source4/auth/kerberos/kerberos.h +++ b/source4/auth/kerberos/kerberos.h @@ -97,7 +97,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, const DATA_BLOB *ticket, char **principal, DATA_BLOB *auth_data, DATA_BLOB *ap_rep, - krb5_keyblock *keyblock); + krb5_keyblock **keyblock); int kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc, const char *principal, const char *password, time_t *expire_time, time_t *kdc_time); @@ -132,5 +132,10 @@ NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx, DATA_BLOB blob, struct smb_krb5_context *smb_krb5_context, krb5_keyblock *keyblock); +krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *server_info, + krb5_context context, + krb5_keyblock *keyblock, + krb5_data *pac); #endif /* HAVE_KRB5 */ diff --git a/source4/auth/kerberos/kerberos_pac.c b/source4/auth/kerberos/kerberos_pac.c index 9d57245798..e1d05b9949 100644 --- a/source4/auth/kerberos/kerberos_pac.c +++ b/source4/auth/kerberos/kerberos_pac.c @@ -28,16 +28,16 @@ #include "system/kerberos.h" #include "system/time.h" #include "system/network.h" +#include "auth/auth.h" #include "auth/kerberos/kerberos.h" #include "librpc/gen_ndr/ndr_krb5pac.h" #include "auth/auth.h" -static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, - DATA_BLOB pac_data, - struct PAC_SIGNATURE_DATA *sig, - struct smb_krb5_context *smb_krb5_context, - krb5_keyblock *keyblock, - uint32_t keyusage) +static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, + DATA_BLOB pac_data, + struct PAC_SIGNATURE_DATA *sig, + krb5_context context, + krb5_keyblock *keyblock) { krb5_error_code ret; krb5_crypto crypto; @@ -48,7 +48,7 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, cksum.checksum.data = sig->signature; - ret = krb5_crypto_init(smb_krb5_context->krb5_context, + ret = krb5_crypto_init(context, keyblock, 0, &crypto); @@ -56,7 +56,7 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, DEBUG(0,("krb5_crypto_init() failed\n")); return NT_STATUS_FOOBAR; } - ret = krb5_verify_checksum(smb_krb5_context->krb5_context, + ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, pac_data.data, @@ -64,10 +64,10 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, &cksum); if (ret) { DEBUG(2, ("PAC Verification failed: %s\n", - smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); + smb_get_krb5_error_message(context, ret, mem_ctx))); } - krb5_crypto_destroy(smb_krb5_context->krb5_context, crypto); + krb5_crypto_destroy(context, crypto); if (ret) { return NT_STATUS_ACCESS_DENIED; @@ -92,6 +92,8 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, DATA_BLOB modified_pac_blob = data_blob_talloc(mem_ctx, blob.data, blob.length); int i; + file_save("/tmp/pac.in", blob.data, blob.length); + status = ndr_pull_struct_blob(&blob, mem_ctx, &pac_data, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); if (!NT_STATUS_IS_OK(status)) { @@ -127,7 +129,7 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, kdc_sig_ptr = &pac_data.buffers[i].info->kdc_cksum; kdc_sig = pac_data.buffers[i].info->kdc_cksum; break; - case PAC_TYPE_UNKNOWN_10: + case PAC_TYPE_LOGON_NAME: break; default: break; @@ -154,11 +156,13 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, memset(&modified_pac_blob.data[modified_pac_blob.length - 44], '\0', 16); - /* verify by servie_key */ - status = kerberos_pac_checksum(mem_ctx, - modified_pac_blob, &srv_sig, - smb_krb5_context, keyblock, 0); + file_save("/tmp/pac.in.blanked", modified_pac_blob.data, modified_pac_blob.length); + /* verify by service_key */ + status = check_pac_checksum(mem_ctx, + modified_pac_blob, &srv_sig, + smb_krb5_context->krb5_context, keyblock); + if (!NT_STATUS_IS_OK(status)) { return status; } @@ -170,3 +174,151 @@ static NTSTATUS kerberos_pac_checksum(TALLOC_CTX *mem_ctx, return status; } +static krb5_error_code make_pac_checksum(TALLOC_CTX *mem_ctx, + DATA_BLOB pac_data, + struct PAC_SIGNATURE_DATA *sig, + krb5_context context, + krb5_keyblock *keyblock) +{ + krb5_error_code ret; + krb5_crypto crypto; + Checksum cksum; + + + ret = krb5_crypto_init(context, + keyblock, + 0, + &crypto); + if (ret) { + DEBUG(0,("krb5_crypto_init() failed\n")); + return ret; + } + ret = krb5_create_checksum(context, + crypto, + KRB5_KU_OTHER_CKSUM, + 0, + pac_data.data, + pac_data.length, + &cksum); + if (ret) { + DEBUG(2, ("PAC Verification failed: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + } + + krb5_crypto_destroy(context, crypto); + + if (ret) { + return ret; + } + + sig->type = cksum.cksumtype; + if (cksum.checksum.length == sizeof(sig->signature)) { + memcpy(sig->signature, cksum.checksum.data, sizeof(sig->signature)); + } + + return 0; +} + + krb5_error_code kerberos_encode_pac(TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *server_info, + krb5_context context, + krb5_keyblock *keyblock, + krb5_data *pac) +{ + NTSTATUS nt_status; + DATA_BLOB tmp_blob = data_blob(NULL, 0); + krb5_error_code ret; + struct PAC_DATA *pac_data = talloc(mem_ctx, struct PAC_DATA); + struct netr_SamBaseInfo *sam; + struct timeval tv = timeval_current(); + + if (!pac_data) { + return ENOMEM; + } + + pac_data->num_buffers = 4; + pac_data->version = 0; + + pac_data->buffers = talloc_array(pac_data, + struct PAC_BUFFER, + pac_data->num_buffers); + + if (!pac_data->buffers) { + talloc_free(pac_data); + return ENOMEM; + } + pac_data->buffers[0].type = PAC_TYPE_LOGON_INFO; + pac_data->buffers[0].info = talloc_zero(pac_data->buffers, + union PAC_INFO); + + nt_status = auth_convert_server_info_sambaseinfo(pac_data->buffers[0].info, + server_info, &sam); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("Getting Samba info failed: %s\n", nt_errstr(nt_status))); + talloc_free(pac_data); + return EINVAL; + } + + pac_data->buffers[0].info->logon_info.info3.base = *sam; + + pac_data->buffers[1].type = PAC_TYPE_LOGON_NAME; + pac_data->buffers[1].info = talloc_zero(pac_data->buffers, + union PAC_INFO); + pac_data->buffers[1].info->logon_name.account_name + = server_info->account_name; + pac_data->buffers[1].info->logon_name.logon_time + = timeval_to_nttime(&tv); + + pac_data->buffers[2].type = PAC_TYPE_KDC_CHECKSUM; + pac_data->buffers[2].info = talloc_zero(pac_data->buffers, + union PAC_INFO); + + pac_data->buffers[3].type = PAC_TYPE_SRV_CHECKSUM; + pac_data->buffers[3].info = talloc_zero(pac_data->buffers, + union PAC_INFO); + + /* First, just get the keytypes filled in (and lengths right, eventually) */ + ret = make_pac_checksum(mem_ctx, tmp_blob, &pac_data->buffers[2].info->srv_cksum, + context, keyblock); + if (ret) { + DEBUG(2, ("making PAC checksum failed: %s\n", + smb_get_krb5_error_message(context, ret, mem_ctx))); + talloc_free(pac_data); + return ret; + } + + /* But wipe out the actual signatures */ + ZERO_STRUCT(pac_data->buffers[2].info->kdc_cksum.signature); + ZERO_STRUCT(pac_data->buffers[3].info->srv_cksum.signature); + + nt_status = ndr_push_struct_blob(&tmp_blob, mem_ctx, pac_data, + (ndr_push_flags_fn_t)ndr_push_PAC_DATA); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("PAC push failed: %s\n", nt_errstr(nt_status))); + talloc_free(pac_data); + return EINVAL; + } + + file_save("/tmp/pac.out.blank", tmp_blob.data, tmp_blob.length); + + /* Then sign the result of the previous push, where the sig was zero'ed out */ + ret = make_pac_checksum(mem_ctx, tmp_blob, &pac_data->buffers[3].info->srv_cksum, + context, keyblock); + + /* And push it out to the world. This relies on determanistic pointer values */ + nt_status = ndr_push_struct_blob(&tmp_blob, mem_ctx, pac_data, + (ndr_push_flags_fn_t)ndr_push_PAC_DATA); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("PAC push failed: %s\n", nt_errstr(nt_status))); + talloc_free(pac_data); + return EINVAL; + } + + file_save("/tmp/pac.out.signed", tmp_blob.data, tmp_blob.length); + + ret = krb5_data_copy(pac, tmp_blob.data, tmp_blob.length); + + talloc_free(pac_data); + return ret; +} + diff --git a/source4/auth/kerberos/kerberos_verify.c b/source4/auth/kerberos/kerberos_verify.c index 01b8a75c95..b140eb6ae9 100644 --- a/source4/auth/kerberos/kerberos_verify.c +++ b/source4/auth/kerberos/kerberos_verify.c @@ -75,7 +75,7 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex const char *service, const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, - krb5_keyblock *keyblock) + krb5_keyblock **keyblock) { krb5_error_code ret = 0; krb5_keytab keytab = NULL; @@ -149,7 +149,9 @@ static krb5_error_code ads_keytab_verify_ticket(TALLOC_CTX *mem_ctx, krb5_contex p_packet->length = ticket->length; p_packet->data = (krb5_pointer)ticket->data; *pp_tkt = NULL; - ret = krb5_rd_req(context, &auth_context, p_packet, kt_entry.principal, keytab, NULL, pp_tkt); + ret = krb5_rd_req_return_keyblock(context, &auth_context, p_packet, + kt_entry.principal, keytab, + NULL, pp_tkt, keyblock); if (ret) { last_error_message = smb_get_krb5_error_message(context, ret, mem_ctx); DEBUG(10, ("ads_keytab_verify_ticket: krb5_rd_req(%s) failed: %s\n", @@ -224,7 +226,7 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx, krb5_principal salt_princ, const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, - krb5_keyblock *keyblock) + krb5_keyblock **keyblock) { krb5_error_code ret = 0; krb5_error_code our_ret; @@ -274,9 +276,10 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx, krb5_free_keyblock(context, key); - our_ret = krb5_rd_req(context, &auth_context, p_packet, - NULL, - NULL, NULL, pp_tkt); + our_ret = krb5_rd_req_return_keyblock(context, &auth_context, p_packet, + NULL, + NULL, NULL, pp_tkt, + keyblock); if (!our_ret) { DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n", @@ -311,7 +314,7 @@ static krb5_error_code ads_secrets_verify_ticket(TALLOC_CTX *mem_ctx, const DATA_BLOB *ticket, char **principal, DATA_BLOB *auth_data, DATA_BLOB *ap_rep, - krb5_keyblock *keyblock) + krb5_keyblock **keyblock) { NTSTATUS sret = NT_STATUS_LOGON_FAILURE; krb5_data packet; |