From 54abd2aa66069e6baf7769c496f46d9dba18db39 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 30 Sep 2005 17:13:37 +0000 Subject: r10656: BIG merge from trunk. Features not copied over * \PIPE\unixinfo * winbindd's {group,alias}membership new functions * winbindd's lookupsids() functionality * swat (trunk changes to be reverted as per discussion with Deryck) (This used to be commit 939c3cb5d78e3a2236209b296aa8aba8bdce32d3) --- source3/libads/authdata.c | 478 ++++++++++++++++++++++++++++++++------- source3/libads/kerberos_verify.c | 94 ++++++-- source3/libads/ldap.c | 4 +- source3/libads/ldap_printer.c | 14 +- source3/libads/sasl.c | 2 +- 5 files changed, 483 insertions(+), 109 deletions(-) (limited to 'source3/libads') diff --git a/source3/libads/authdata.c b/source3/libads/authdata.c index 2cc6c6ebae..2e7866c055 100644 --- a/source3/libads/authdata.c +++ b/source3/libads/authdata.c @@ -2,6 +2,11 @@ Unix SMB/CIFS implementation. kerberos authorization data (PAC) utility library Copyright (C) Jim McDonough 2003 + Copyright (C) Andrew Bartlett 2004-2005 + Copyright (C) Andrew Tridgell 2001 + Copyright (C) Luke Howard 2002-2003 + Copyright (C) Stefan Metzmacher 2004-2005 + Copyright (C) Guenther Deschner 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 @@ -22,27 +27,6 @@ #ifdef HAVE_KRB5 -static DATA_BLOB unwrap_pac(DATA_BLOB *auth_data) -{ - DATA_BLOB pac_contents; - ASN1_DATA data; - int data_type; - - asn1_load(&data, *auth_data); - asn1_start_tag(&data, ASN1_SEQUENCE(0)); - asn1_start_tag(&data, ASN1_SEQUENCE(0)); - asn1_start_tag(&data, ASN1_CONTEXT(0)); - asn1_read_Integer(&data, &data_type); - asn1_end_tag(&data); - asn1_start_tag(&data, ASN1_CONTEXT(1)); - asn1_read_OctetString(&data, &pac_contents); - asn1_end_tag(&data); - asn1_end_tag(&data); - asn1_end_tag(&data); - asn1_free(&data); - return pac_contents; -} - static BOOL pac_io_logon_name(const char *desc, PAC_LOGON_NAME *logon_name, prs_struct *ps, int depth) { @@ -75,6 +59,8 @@ static BOOL pac_io_logon_name(const char *desc, PAC_LOGON_NAME *logon_name, } + +#if 0 /* Unused (handled now in net_io_user_info3()) - Guenther */ static BOOL pac_io_krb_sids(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr, prs_struct *ps, int depth) { @@ -159,6 +145,7 @@ static BOOL pac_io_krb_sid_and_attr_array(const char *desc, return True; } +#endif static BOOL pac_io_group_membership(const char *desc, GROUP_MEMBERSHIP *membership, @@ -216,27 +203,34 @@ static BOOL pac_io_group_membership_array(const char *desc, } +#if 0 /* Unused, replaced using an expanded net_io_user_info3() now - Guenther */ static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info, prs_struct *ps, int depth) { - uint32 garbage; + uint32 garbage, i; + if (NULL == info) return False; prs_debug(ps, depth, desc, "pac_io_pac_logon_info"); depth++; - if (!prs_uint32("unknown", ps, depth, &garbage)) + if (!prs_align(ps)) return False; - if (!prs_uint32("unknown", ps, depth, &garbage)) + if (!prs_uint32("unknown", ps, depth, &garbage)) /* 00081001 */ + return False; + if (!prs_uint32("unknown", ps, depth, &garbage)) /* cccccccc */ return False; if (!prs_uint32("bufferlen", ps, depth, &garbage)) return False; - if (!prs_uint32("bufferlenhi", ps, depth, &garbage)) + if (!prs_uint32("bufferlenhi", ps, depth, &garbage)) /* 00000000 */ return False; + if (!prs_uint32("pointer", ps, depth, &garbage)) return False; + if (!prs_align(ps)) + return False; if (!smb_io_time("logon_time", &info->logon_time, ps, depth)) return False; if (!smb_io_time("logoff_time", &info->logoff_time, ps, depth)) @@ -270,7 +264,7 @@ static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info, if (!prs_uint16("logon_count", ps, depth, &info->logon_count)) return False; - if (!prs_uint16("reserved12", ps, depth, &info->reserved12)) + if (!prs_uint16("bad_password_count", ps, depth, &info->bad_password_count)) return False; if (!prs_uint32("user_rid", ps, depth, &info->user_rid)) return False; @@ -287,13 +281,7 @@ static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info, if (!prs_uint32("user_flags", ps, depth, &info->user_flags)) return False; - if (!prs_uint32("reserved13.0", ps, depth, &info->reserved13[0])) - return False; - if (!prs_uint32("reserved13.1", ps, depth, &info->reserved13[1])) - return False; - if (!prs_uint32("reserved13.2", ps, depth, &info->reserved13[2])) - return False; - if (!prs_uint32("reserved13.3", ps, depth, &info->reserved13[3])) + if (!prs_uint8s(False, "session_key", ps, depth, info->session_key, 16)) return False; if (!smb_io_unihdr("hdr_dom_controller", @@ -306,30 +294,17 @@ static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info, if (!prs_uint32("ptr_dom_sid", ps, depth, &info->ptr_dom_sid)) return False; - if (!prs_uint32("reserved16.0", ps, depth, &info->reserved16[0])) - return False; - if (!prs_uint32("reserved16.1", ps, depth, &info->reserved16[1])) + if (!prs_uint8s(False, "lm_session_key", ps, depth, info->lm_session_key, 8)) return False; - /* might be acb_info */ - if (!prs_uint32("reserved17", ps, depth, &info->reserved17)) + if (!prs_uint32("acct_flags", ps, depth, &info->acct_flags)) return False; - - if (!prs_uint32("reserved18.0", ps, depth, &info->reserved18[0])) - return False; - if (!prs_uint32("reserved18.1", ps, depth, &info->reserved18[1])) - return False; - if (!prs_uint32("reserved18.2", ps, depth, &info->reserved18[2])) - return False; - if (!prs_uint32("reserved18.3", ps, depth, &info->reserved18[3])) - return False; - if (!prs_uint32("reserved18.4", ps, depth, &info->reserved18[4])) - return False; - if (!prs_uint32("reserved18.5", ps, depth, &info->reserved18[5])) - return False; - if (!prs_uint32("reserved18.6", ps, depth, &info->reserved18[6])) - return False; + for (i = 0; i < 7; i++) + { + if (!prs_uint32("unkown", ps, depth, &info->unknown[i])) /* unknown */ + return False; + } if (!prs_uint32("sid_count", ps, depth, &info->sid_count)) return False; @@ -395,44 +370,109 @@ static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info, &info->res_group_dom_sid, ps, depth)) return False; - if (info->ptr_res_groups) + if (info->ptr_res_groups) { + + if (!(info->user_flgs & LOGON_RESOURCE_GROUPS)) { + DEBUG(0,("user_flgs attribute does not have LOGON_RESOURCE_GROUPS\n")); + /* return False; */ + } + if (!pac_io_group_membership_array("res group membership", &info->res_groups, info->res_group_count, ps, depth)) return False; + } + + return True; +} +#endif + +static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info, + prs_struct *ps, int depth) +{ + uint32 garbage; + BOOL kerb_validation_info = True; + + if (NULL == info) + return False; + + prs_debug(ps, depth, desc, "pac_io_pac_logon_info"); + depth++; + + if (!prs_align(ps)) + return False; + if (!prs_uint32("unknown", ps, depth, &garbage)) /* 00081001 */ + return False; + if (!prs_uint32("unknown", ps, depth, &garbage)) /* cccccccc */ + return False; + if (!prs_uint32("bufferlen", ps, depth, &garbage)) + return False; + if (!prs_uint32("bufferlenhi", ps, depth, &garbage)) /* 00000000 */ + return False; + + if(!net_io_user_info3("", &info->info3, ps, depth, 3, kerb_validation_info)) + return False; + + if (info->info3.ptr_res_group_dom_sid) { + if (!smb_io_dom_sid2("res_group_dom_sid", + &info->res_group_dom_sid, ps, depth)) + return False; + } + + if (info->info3.ptr_res_groups) { + + if (!(info->info3.user_flgs & LOGON_RESOURCE_GROUPS)) { + DEBUG(0,("user_flgs attribute does not have LOGON_RESOURCE_GROUPS\n")); + /* return False; */ + } + + if (!pac_io_group_membership_array("res group membership", + &info->res_groups, + info->info3.res_group_count, + ps, depth)) + return False; + } return True; } + static BOOL pac_io_pac_signature_data(const char *desc, PAC_SIGNATURE_DATA *data, uint32 length, prs_struct *ps, int depth) { uint32 siglen = length - sizeof(uint32); - if (NULL == data) - return False; - prs_debug(ps, depth, desc, "pac_io_pac_signature_data"); depth++; + + if (data == NULL) + return False; + if (!prs_align(ps)) + return False; if (!prs_uint32("type", ps, depth, &data->type)) return False; - if (UNMARSHALLING(ps)) { - data->signature = PRS_ALLOC_MEM(ps, unsigned char, siglen); - if (!data->signature) { + + if (UNMARSHALLING(ps) && length) { + data->signature.buffer = PRS_ALLOC_MEM(ps, uint8, siglen); + if (!data->signature.buffer) { DEBUG(3, ("No memory available\n")); return False; } } - if (!prs_uint8s(False, "signature", ps, depth, data->signature,siglen)) + + data->signature.buf_len = siglen; + + if (!prs_uint8s(False, "signature", ps, depth, data->signature.buffer, data->signature.buf_len)) return False; + return True; } -static BOOL pac_io_pac_info_hdr_ctr(const char *desc, PAC_INFO_HDR *hdr, +static BOOL pac_io_pac_info_hdr_ctr(const char *desc, PAC_BUFFER *hdr, prs_struct *ps, int depth) { if (NULL == hdr) @@ -445,8 +485,8 @@ static BOOL pac_io_pac_info_hdr_ctr(const char *desc, PAC_INFO_HDR *hdr, return False; if (hdr->offset != prs_offset(ps)) { - DEBUG(5, ("offset in header(x%x) and data(x%x) do not match\n", - hdr->offset, prs_offset(ps))); + DEBUG(5,("offset in header(x%x) and data(x%x) do not match, correcting\n", + hdr->offset, prs_offset(ps))); prs_set_offset(ps, hdr->offset); } @@ -518,10 +558,15 @@ static BOOL pac_io_pac_info_hdr_ctr(const char *desc, PAC_INFO_HDR *hdr, prs_set_offset(ps, prs_offset(ps) + hdr->size); } +#if 0 + /* obscure pad */ + if (!prs_uint32("pad", ps, depth, &hdr->pad)) + return False; +#endif return True; } -static BOOL pac_io_pac_info_hdr(const char *desc, PAC_INFO_HDR *hdr, +static BOOL pac_io_pac_info_hdr(const char *desc, PAC_BUFFER *hdr, prs_struct *ps, int depth) { if (NULL == hdr) @@ -563,19 +608,19 @@ static BOOL pac_io_pac_data(const char *desc, PAC_DATA *data, return False; if (UNMARSHALLING(ps) && data->num_buffers > 0) { - if ((data->pac_info_hdr_ptr = PRS_ALLOC_MEM(ps, PAC_INFO_HDR, data->num_buffers)) == NULL) { + if ((data->pac_buffer = PRS_ALLOC_MEM(ps, PAC_BUFFER, data->num_buffers)) == NULL) { return False; } } for (i=0; inum_buffers; i++) { - if (!pac_io_pac_info_hdr(desc, &data->pac_info_hdr_ptr[i], ps, + if (!pac_io_pac_info_hdr(desc, &data->pac_buffer[i], ps, depth)) return False; } for (i=0; inum_buffers; i++) { - if (!pac_io_pac_info_hdr_ctr(desc, &data->pac_info_hdr_ptr[i], + if (!pac_io_pac_info_hdr_ctr(desc, &data->pac_buffer[i], ps, depth)) return False; } @@ -583,25 +628,300 @@ static BOOL pac_io_pac_data(const char *desc, PAC_DATA *data, return True; } -PAC_DATA *decode_pac_data(DATA_BLOB *auth_data, TALLOC_CTX *ctx) +static NTSTATUS check_pac_checksum(TALLOC_CTX *mem_ctx, + DATA_BLOB pac_data, + PAC_SIGNATURE_DATA *sig, + krb5_context context, + krb5_keyblock *keyblock) +{ + krb5_error_code ret; + krb5_checksum cksum; + krb5_keyusage usage = 0; + + smb_krb5_checksum_from_pac_sig(&cksum, sig); + +#ifdef HAVE_KRB5_KU_OTHER_CKSUM /* Heimdal */ + usage = KRB5_KU_OTHER_CKSUM; +#elif defined(HAVE_KRB5_KEYUSAGE_APP_DATA_CKSUM) /* MIT */ + usage = KRB5_KEYUSAGE_APP_DATA_CKSUM; +#else +#error UNKNOWN_KRB5_KEYUSAGE +#endif + + ret = smb_krb5_verify_checksum(context, + keyblock, + usage, + &cksum, + pac_data.data, + pac_data.length); + + if (ret) { + DEBUG(2,("check_pac_checksum: PAC Verification failed: %s (%d)\n", + error_message(ret), ret)); + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} + +static NTSTATUS parse_pac_data(TALLOC_CTX *mem_ctx, DATA_BLOB *pac_data_blob, PAC_DATA *pac_data) { - DATA_BLOB pac_data_blob = unwrap_pac(auth_data); prs_struct ps; - PAC_DATA *pac_data; + PAC_DATA *my_pac; - DEBUG(5,("dump_pac_data\n")); - prs_init(&ps, pac_data_blob.length, ctx, UNMARSHALL); - prs_copy_data_in(&ps, (char *)pac_data_blob.data, pac_data_blob.length); - prs_set_offset(&ps, 0); + if (!prs_init(&ps, pac_data_blob->length, mem_ctx, UNMARSHALL)) + return NT_STATUS_NO_MEMORY; - data_blob_free(&pac_data_blob); + if (!prs_copy_data_in(&ps, (char *)pac_data_blob->data, pac_data_blob->length)) + return NT_STATUS_INVALID_PARAMETER; + + prs_set_offset(&ps, 0); - pac_data = TALLOC_ZERO_P(ctx, PAC_DATA); - pac_io_pac_data("pac data", pac_data, &ps, 0); + my_pac = TALLOC_ZERO_P(mem_ctx, PAC_DATA); + if (!pac_io_pac_data("pac data", my_pac, &ps, 0)) + return NT_STATUS_INVALID_PARAMETER; prs_mem_free(&ps); - return pac_data; + *pac_data = *my_pac; + + return NT_STATUS_OK; +} + +/* just for debugging, will be removed later - Guenther */ +char *pac_group_attr_string(uint32 attr) +{ + fstring name = ""; + + if (!attr) + return NULL; + + if (attr & SE_GROUP_MANDATORY) fstrcat(name, "SE_GROUP_MANDATORY "); + if (attr & SE_GROUP_ENABLED_BY_DEFAULT) fstrcat(name, "SE_GROUP_ENABLED_BY_DEFAULT "); + if (attr & SE_GROUP_ENABLED) fstrcat(name, "SE_GROUP_ENABLED "); + if (attr & SE_GROUP_OWNER) fstrcat(name, "SE_GROUP_OWNER "); + if (attr & SE_GROUP_USE_FOR_DENY_ONLY) fstrcat(name, "SE_GROUP_USE_FOR_DENY_ONLY "); + if (attr & SE_GROUP_LOGON_ID) fstrcat(name, "SE_GROUP_LOGON_ID "); + if (attr & SE_GROUP_RESOURCE) fstrcat(name, "SE_GROUP_RESOURCE "); + + return SMB_STRDUP(name); +} + +/* just for debugging, will be removed later - Guenther */ +static void dump_pac_logon_info(PAC_LOGON_INFO *logon_info) { + + DOM_SID dom_sid, res_group_dom_sid; + int i; + char *attr_string; + uint32 user_flgs = logon_info->info3.user_flgs; + + if (logon_info->info3.ptr_res_group_dom_sid) { + sid_copy(&res_group_dom_sid, &logon_info->res_group_dom_sid.sid); + } + sid_copy(&dom_sid, &logon_info->info3.dom_sid.sid); + + DEBUG(10,("The PAC:\n")); + + DEBUGADD(10,("\tUser Flags: 0x%x (%d)\n", user_flgs, user_flgs)); + if (user_flgs & LOGON_EXTRA_SIDS) + DEBUGADD(10,("\tUser Flags: LOGON_EXTRA_SIDS 0x%x (%d)\n", LOGON_EXTRA_SIDS, LOGON_EXTRA_SIDS)); + if (user_flgs & LOGON_RESOURCE_GROUPS) + DEBUGADD(10,("\tUser Flags: LOGON_RESOURCE_GROUPS 0x%x (%d)\n", LOGON_RESOURCE_GROUPS, LOGON_RESOURCE_GROUPS)); + DEBUGADD(10,("\tUser SID: %s-%d\n", sid_string_static(&dom_sid), logon_info->info3.user_rid)); + DEBUGADD(10,("\tGroup SID: %s-%d\n", sid_string_static(&dom_sid), logon_info->info3.group_rid)); + + DEBUGADD(10,("\tGroup Membership (Global and Universal Groups of own domain):\n")); + for (i = 0; i < logon_info->info3.num_groups; i++) { + attr_string = pac_group_attr_string(logon_info->info3.gids[i].attr); + DEBUGADD(10,("\t\t%d: sid: %s-%d\n\t\t attr: 0x%x == %s\n", + i, sid_string_static(&dom_sid), + logon_info->info3.gids[i].g_rid, + logon_info->info3.gids[i].attr, + attr_string)); + SAFE_FREE(attr_string); + } + + DEBUGADD(10,("\tGroup Membership (Domain Local Groups and Groups from Trusted Domains):\n")); + for (i = 0; i < logon_info->info3.num_other_sids; i++) { + attr_string = pac_group_attr_string(logon_info->info3.other_sids_attrib[i]); + DEBUGADD(10,("\t\t%d: sid: %s\n\t\t attr: 0x%x == %s\n", + i, sid_string_static(&logon_info->info3.other_sids[i].sid), + logon_info->info3.other_sids_attrib[i], + attr_string)); + SAFE_FREE(attr_string); + } + + DEBUGADD(10,("\tGroup Membership (Ressource Groups (SID History ?)):\n")); + for (i = 0; i < logon_info->info3.res_group_count; i++) { + attr_string = pac_group_attr_string(logon_info->res_groups.group_membership[i].attrs); + DEBUGADD(10,("\t\t%d: sid: %s-%d\n\t\t attr: 0x%x == %s\n", + i, sid_string_static(&res_group_dom_sid), + logon_info->res_groups.group_membership[i].rid, + logon_info->res_groups.group_membership[i].attrs, + attr_string)); + SAFE_FREE(attr_string); + } +} + +NTSTATUS decode_pac_data(TALLOC_CTX *mem_ctx, + DATA_BLOB *pac_data_blob, + krb5_context context, + krb5_keyblock *service_keyblock, + krb5_const_principal client_principal, + time_t tgs_authtime, + PAC_DATA **pac_data) + +{ + DATA_BLOB modified_pac_blob; + PAC_DATA *my_pac; + NTSTATUS nt_status; + krb5_error_code ret; + PAC_SIGNATURE_DATA *srv_sig = NULL; + PAC_SIGNATURE_DATA *kdc_sig = NULL; + PAC_LOGON_NAME *logon_name = NULL; + PAC_LOGON_INFO *logon_info = NULL; + krb5_principal client_principal_pac; + NTTIME tgs_authtime_nttime; + int i, srv_sig_pos = 0, kdc_sig_pos = 0; + fstring username; + + *pac_data = NULL; + + my_pac = talloc(mem_ctx, PAC_DATA); + if (!my_pac) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = parse_pac_data(mem_ctx, pac_data_blob, my_pac); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0,("decode_pac_data: failed to parse PAC\n")); + return nt_status; + } + + modified_pac_blob = data_blob_talloc(mem_ctx, pac_data_blob->data, pac_data_blob->length); + + if (my_pac->num_buffers < 4) { + nt_status = NT_STATUS_INVALID_PARAMETER; + goto out; + } + + /* store signatures */ + for (i=0; i < my_pac->num_buffers; i++) { + + switch (my_pac->pac_buffer[i].type) { + + case PAC_TYPE_SERVER_CHECKSUM: + if (!my_pac->pac_buffer[i].ctr->pac.srv_cksum) { + break; + } + + srv_sig = my_pac->pac_buffer[i].ctr->pac.srv_cksum; + + /* get position of signature buffer */ + srv_sig_pos = my_pac->pac_buffer[i].offset; + srv_sig_pos += sizeof(uint32); + + break; + + case PAC_TYPE_PRIVSVR_CHECKSUM: + if (!my_pac->pac_buffer[i].ctr->pac.privsrv_cksum) { + break; + } + + kdc_sig = my_pac->pac_buffer[i].ctr->pac.privsrv_cksum; + + /* get position of signature buffer */ + kdc_sig_pos = my_pac->pac_buffer[i].offset; + kdc_sig_pos += sizeof(uint32); + + break; + + case PAC_TYPE_LOGON_NAME: + if (!my_pac->pac_buffer[i].ctr->pac.logon_name) { + break; + } + + logon_name = my_pac->pac_buffer[i].ctr->pac.logon_name; + break; + + case PAC_TYPE_LOGON_INFO: + if (!my_pac->pac_buffer[i].ctr->pac.logon_info) { + break; + } + + logon_info = my_pac->pac_buffer[i].ctr->pac.logon_info; + break; + } + + } + + if (!srv_sig || !kdc_sig || !logon_name || !logon_info) { + nt_status = NT_STATUS_INVALID_PARAMETER; + goto out; + } + + /* zero PAC_SIGNATURE_DATA signature buffer */ + memset(&modified_pac_blob.data[srv_sig_pos], '\0', srv_sig->signature.buf_len); + memset(&modified_pac_blob.data[kdc_sig_pos], '\0', kdc_sig->signature.buf_len); + + /* check server signature */ + nt_status = check_pac_checksum(mem_ctx, modified_pac_blob, srv_sig, context, service_keyblock); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0,("decode_pac_data: failed to verify PAC server signature\n")); + goto out; + } + + /* Convert to NT time, so as not to loose accuracy in comparison */ + unix_to_nt_time(&tgs_authtime_nttime, tgs_authtime); + + if (!nt_time_equals(&tgs_authtime_nttime, &logon_name->logon_time)) { + + DEBUG(2,("decode_pac_data: Logon time mismatch between ticket and PAC!\n")); + DEBUGADD(2, ("decode_pac_data: PAC: %s\n", + http_timestring(nt_time_to_unix(&logon_name->logon_time)))); + DEBUGADD(2, ("decode_pac_data: Ticket: %s\n", + http_timestring(nt_time_to_unix(&tgs_authtime_nttime)))); + + nt_status = NT_STATUS_ACCESS_DENIED; + goto out; + } + + if (!logon_name->len) { + DEBUG(2,("decode_pac_data: No Logon Name available\n")); + nt_status = NT_STATUS_INVALID_PARAMETER; + goto out; + } + rpcstr_pull(username, logon_name->username, sizeof(username), -1, STR_TERMINATE); + + ret = smb_krb5_parse_name_norealm(context, username, &client_principal_pac); + if (ret) { + DEBUG(2,("decode_pac_data: Could not parse name from incoming PAC: [%s]: %s\n", + username, error_message(ret))); + nt_status = NT_STATUS_INVALID_PARAMETER; + goto out; + } + + if (!smb_krb5_principal_compare_any_realm(context, client_principal, client_principal_pac)) { + DEBUG(2,("decode_pac_data: Name in PAC [%s] does not match principal name in ticket\n", + username)); + nt_status = NT_STATUS_ACCESS_DENIED; + goto out; + } + + DEBUG(10,("Successfully validated Kerberos PAC\n")); + + dump_pac_logon_info(logon_info); + + *pac_data = my_pac; + + nt_status = NT_STATUS_OK; + +out: + if (client_principal_pac) { + krb5_free_principal(context, client_principal_pac); + } + + return nt_status; } #endif diff --git a/source3/libads/kerberos_verify.c b/source3/libads/kerberos_verify.c index 770d129e5d..6a5c6b6a49 100644 --- a/source3/libads/kerberos_verify.c +++ b/source3/libads/kerberos_verify.c @@ -4,8 +4,9 @@ Copyright (C) Andrew Tridgell 2001 Copyright (C) Remus Koos 2001 Copyright (C) Luke Howard 2003 - Copyright (C) Guenther Deschner 2003 + Copyright (C) Guenther Deschner 2003, 2005 Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003 + Copyright (C) Andrew Bartlett 2004-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 @@ -37,7 +38,8 @@ const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int ); ***********************************************************************************/ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context auth_context, - const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt) + const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, + krb5_keyblock **keyblock) { krb5_error_code ret = 0; BOOL auth_ok = False; @@ -100,12 +102,18 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut 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_from_keytab(context, &auth_context, p_packet, + kt_entry.principal, keytab, + NULL, pp_tkt, keyblock); + if (ret) { - DEBUG(10, ("ads_keytab_verify_ticket: krb5_rd_req(%s) failed: %s\n", + DEBUG(10,("ads_keytab_verify_ticket: " + "krb5_rd_req_return_keyblock_from_keytab(%s) failed: %s\n", entry_princ_s, error_message(ret))); } else { - DEBUG(3,("ads_keytab_verify_ticket: krb5_rd_req succeeded for principal %s\n", + DEBUG(3,("ads_keytab_verify_ticket: " + "krb5_rd_req_return_keyblock_from_keytab succeeded for principal %s\n", entry_princ_s)); auth_ok = True; break; @@ -172,8 +180,9 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut ***********************************************************************************/ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context auth_context, - krb5_principal host_princ, - const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt) + krb5_principal host_princ, + const DATA_BLOB *ticket, krb5_data *p_packet, krb5_ticket **pp_tkt, + krb5_keyblock **keyblock) { krb5_error_code ret = 0; BOOL auth_ok = False; @@ -182,6 +191,8 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au krb5_enctype *enctypes = NULL; int i; + ZERO_STRUCTP(keyblock); + if (!secrets_init()) { DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n")); return False; @@ -222,20 +233,23 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au krb5_auth_con_setuseruserkey(context, auth_context, key); - krb5_free_keyblock(context, key); - if (!(ret = krb5_rd_req(context, &auth_context, p_packet, NULL, NULL, NULL, pp_tkt))) { DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n", (unsigned int)enctypes[i] )); auth_ok = True; + krb5_copy_keyblock(context, key, keyblock); + krb5_free_keyblock(context, key); break; } DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10, ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n", (unsigned int)enctypes[i], error_message(ret))); + + krb5_free_keyblock(context, key); + } out: @@ -251,27 +265,33 @@ static BOOL ads_secrets_verify_ticket(krb5_context context, krb5_auth_context au authorization_data if available. ***********************************************************************************/ -NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, - char **principal, DATA_BLOB *auth_data, +NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, + const char *realm, const DATA_BLOB *ticket, + char **principal, PAC_DATA **pac_data, DATA_BLOB *ap_rep, DATA_BLOB *session_key) { NTSTATUS sret = NT_STATUS_LOGON_FAILURE; + DATA_BLOB auth_data; krb5_context context = NULL; krb5_auth_context auth_context = NULL; krb5_data packet; krb5_ticket *tkt = NULL; krb5_rcache rcache = NULL; + krb5_keyblock *keyblock = NULL; + time_t authtime; int ret; krb5_principal host_princ = NULL; + krb5_const_principal client_principal = NULL; char *host_princ_s = NULL; BOOL got_replay_mutex = False; BOOL auth_ok = False; + BOOL got_auth_data = False; ZERO_STRUCT(packet); - ZERO_STRUCTP(auth_data); + ZERO_STRUCT(auth_data); ZERO_STRUCTP(ap_rep); ZERO_STRUCTP(session_key); @@ -335,20 +355,30 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, } if (lp_use_kerberos_keytab()) { - auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &packet, &tkt); + auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &packet, &tkt, &keyblock); } if (!auth_ok) { auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ, - ticket, &packet, &tkt); + ticket, &packet, &tkt, &keyblock); } release_server_mutex(); got_replay_mutex = False; +#if 0 + /* Heimdal leaks here, if we fix the leak, MIT crashes */ + if (rcache) { + krb5_rc_close(context, rcache); + } +#endif + if (!auth_ok) { DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", error_message(ret))); goto out; + } else { + authtime = get_authtime_from_tkt(tkt); + client_principal = get_principal_from_tkt(tkt); } ret = krb5_mk_rep(context, auth_context, &packet); @@ -369,20 +399,40 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, file_save("/tmp/ticket.dat", ticket->data, ticket->length); #endif - get_auth_data_from_tkt(auth_data, tkt); + /* continue when no PAC is retrieved + (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set) */ - { - TALLOC_CTX *ctx = talloc_init("pac data"); - decode_pac_data(auth_data, ctx); - talloc_destroy(ctx); + got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt); + if (!got_auth_data) { + DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n")); + } + + if (got_auth_data && pac_data != NULL) { + + sret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, pac_data); + if (!NT_STATUS_IS_OK(sret)) { + DEBUG(0,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(sret))); + goto out; + } + data_blob_free(&auth_data); } #if 0 +#if defined(HAVE_KRB5_TKT_ENC_PART2) + /* MIT */ if (tkt->enc_part2) { file_save("/tmp/authdata.dat", tkt->enc_part2->authorization_data[0]->contents, tkt->enc_part2->authorization_data[0]->length); } +#else + /* Heimdal */ + if (tkt->ticket.authorization_data) { + file_save("/tmp/authdata.dat", + tkt->ticket.authorization_data->val->ad_data.data, + tkt->ticket.authorization_data->val->ad_data.length); + } +#endif #endif if ((ret = krb5_unparse_name(context, get_principal_from_tkt(tkt), @@ -402,7 +452,7 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, } if (!NT_STATUS_IS_OK(sret)) { - data_blob_free(auth_data); + data_blob_free(&auth_data); } if (!NT_STATUS_IS_OK(sret)) { @@ -413,6 +463,10 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket, krb5_free_principal(context, host_princ); } + if (keyblock) { + krb5_free_keyblock(context, keyblock); + } + if (tkt != NULL) { krb5_free_ticket(context, tkt); } diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 81afd7f49e..bf402b3499 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -2104,7 +2104,7 @@ char **ads_pull_strings_range(ADS_STRUCT *ads, if ((*num_strings) != range_start) { DEBUG(1, ("ads_pull_strings_range: Range attribute (%s) doesn't start at %u, but at %lu" " - aborting range retreival\n", - range_attr, *num_strings + 1, range_start)); + range_attr, (unsigned int)(*num_strings) + 1, range_start)); ldap_memfree(range_attr); *more_strings = False; return NULL; @@ -2140,7 +2140,7 @@ char **ads_pull_strings_range(ADS_STRUCT *ads, *next_attribute = talloc_asprintf(mem_ctx, "%s;range=%d-*", field, - *num_strings); + (int)*num_strings); if (!*next_attribute) { DEBUG(1, ("talloc_asprintf for next attribute failed!\n")); diff --git a/source3/libads/ldap_printer.c b/source3/libads/ldap_printer.c index db544fe209..d6ac09d22b 100644 --- a/source3/libads/ldap_printer.c +++ b/source3/libads/ldap_printer.c @@ -258,7 +258,7 @@ static void map_regval_to_ads(TALLOC_CTX *ctx, ADS_MODLIST *mods, } -WERROR get_remote_printer_publishing_data(struct cli_state *cli, +WERROR get_remote_printer_publishing_data(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, ADS_MODLIST *mods, const char *printer) @@ -269,16 +269,16 @@ WERROR get_remote_printer_publishing_data(struct cli_state *cli, uint32 i; POLICY_HND pol; - asprintf(&servername, "\\\\%s", cli->desthost); + asprintf(&servername, "\\\\%s", cli->cli->desthost); asprintf(&printername, "%s\\%s", servername, printer); if (!servername || !printername) { DEBUG(3, ("Insufficient memory\n")); return WERR_NOMEM; } - result = cli_spoolss_open_printer_ex(cli, mem_ctx, printername, + result = rpccli_spoolss_open_printer_ex(cli, mem_ctx, printername, "", MAXIMUM_ALLOWED_ACCESS, - servername, cli->user_name, &pol); + servername, cli->cli->user_name, &pol); if (!W_ERROR_IS_OK(result)) { DEBUG(3, ("Unable to open printer %s, error is %s.\n", printername, dos_errstr(result))); @@ -288,7 +288,7 @@ WERROR get_remote_printer_publishing_data(struct cli_state *cli, if ( !(dsdriver_ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) ) return WERR_NOMEM; - result = cli_spoolss_enumprinterdataex(cli, mem_ctx, &pol, SPOOL_DSDRIVER_KEY, dsdriver_ctr); + result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &pol, SPOOL_DSDRIVER_KEY, dsdriver_ctr); if (!W_ERROR_IS_OK(result)) { DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n", @@ -305,7 +305,7 @@ WERROR get_remote_printer_publishing_data(struct cli_state *cli, if ( !(dsspooler_ctr = TALLOC_ZERO_P( mem_ctx, REGVAL_CTR )) ) return WERR_NOMEM; - result = cli_spoolss_enumprinterdataex(cli, mem_ctx, &pol, SPOOL_DSSPOOLER_KEY, dsspooler_ctr); + result = rpccli_spoolss_enumprinterdataex(cli, mem_ctx, &pol, SPOOL_DSSPOOLER_KEY, dsspooler_ctr); if (!W_ERROR_IS_OK(result)) { DEBUG(3, ("Unable to do enumdataex on %s, error is %s.\n", @@ -323,7 +323,7 @@ WERROR get_remote_printer_publishing_data(struct cli_state *cli, TALLOC_FREE( dsdriver_ctr ); TALLOC_FREE( dsspooler_ctr ); - cli_spoolss_close_printer(cli, mem_ctx, &pol); + rpccli_spoolss_close_printer(cli, mem_ctx, &pol); return result; } diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c index 8fa62a5ade..72cbf7264e 100644 --- a/source3/libads/sasl.c +++ b/source3/libads/sasl.c @@ -142,7 +142,7 @@ static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *princip DATA_BLOB session_key = data_blob(NULL, 0); int rc; - rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key); + rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0); if (rc) { return ADS_ERROR_KRB5(rc); -- cgit