diff options
-rw-r--r-- | source3/Makefile.in | 2 | ||||
-rw-r--r-- | source3/include/authdata.h | 131 | ||||
-rw-r--r-- | source3/include/ntdomain.h | 4 | ||||
-rw-r--r-- | source3/libads/authdata.c | 495 | ||||
-rw-r--r-- | source3/libads/kerberos_verify.c | 6 |
5 files changed, 636 insertions, 2 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 33c687fa96..fc18fc2ff2 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -195,7 +195,7 @@ LIBADS_OBJ = libads/ldap.o libads/ldap_printer.o libads/sasl.o \ libads/krb5_setpw.o libads/ldap_user.o \ libads/ads_struct.o libads/ads_status.o \ libads/disp_sec.o libads/ads_utils.o libads/ldap_utils.o \ - libads/ads_ldap.o + libads/ads_ldap.o libads/authdata.o LIBADS_SERVER_OBJ = libads/util.o libads/kerberos_verify.o diff --git a/source3/include/authdata.h b/source3/include/authdata.h new file mode 100644 index 0000000000..dc9f217549 --- /dev/null +++ b/source3/include/authdata.h @@ -0,0 +1,131 @@ +/* + Unix SMB/CIFS implementation. + Kerberos authorization data + Copyright (C) Jim McDonough 2003 + + + 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. +*/ + +#ifndef _AUTHDATA_H +#define _AUTHDATA_H + +#include "rpc_misc.h" + +#define PAC_TYPE_LOGON_INFO 1 +#define PAC_TYPE_SERVER_CHECKSUM 6 +#define PAC_TYPE_PRIVSVR_CHECKSUM 7 + +typedef struct pac_signature_data { + uint32 type; + uint8 *signature; +} PAC_SIGNATURE_DATA; + +typedef struct krb_sid_and_attrs { + uint32 sid_ptr; + uint32 attrs; + DOM_SID2 *sid; +} KRB_SID_AND_ATTRS; + +typedef struct krb_sid_and_attr_array { + uint32 count; + KRB_SID_AND_ATTRS *krb_sid_and_attrs; +} KRB_SID_AND_ATTR_ARRAY; + + +/* This is awfully similar to a samr_user_info_23, but not identical. + Many of the field names have been swiped from there, because it is + so similar that they are likely the same, but many have been verified. + Some are in a different order, though... */ +typedef struct pac_logon_info { + NTTIME logon_time; /* logon time */ + NTTIME logoff_time; /* logoff time */ + NTTIME kickoff_time; /* kickoff time */ + NTTIME pass_last_set_time; /* password last set time */ + NTTIME pass_can_change_time; /* password can change time */ + NTTIME pass_must_change_time; /* password must change time */ + + UNIHDR hdr_user_name; /* user name unicode string header */ + UNIHDR hdr_full_name; /* user's full name unicode string header */ + UNIHDR hdr_logon_script; /* these last 4 appear to be in a different */ + UNIHDR hdr_profile_path; /* order than in the info23 */ + UNIHDR hdr_home_dir; + UNIHDR hdr_dir_drive; + + uint16 logon_count; /* number of times user has logged onto domain */ + uint16 reserved12; + + uint32 user_rid; + uint32 group_rid; + uint32 group_count; + uint32 group_membership_ptr; + uint32 user_flags; + + uint32 reserved13[4]; + UNIHDR hdr_dom_controller; + UNIHDR hdr_dom_name; + + uint32 ptr_dom_sid; + + uint32 reserved16[2]; + uint32 reserved17; /* looks like it may be acb_info */ + uint32 reserved18[7]; + + uint32 sid_count; + uint32 ptr_extra_sids; + + uint32 ptr_res_group_dom_sid; + uint32 res_group_count; + uint32 ptr_res_group_sids; + + UNISTR2 uni_user_name; /* user name unicode string header */ + UNISTR2 uni_full_name; /* user's full name unicode string header */ + UNISTR2 uni_logon_script; /* these last 4 appear to be in a different*/ + UNISTR2 uni_profile_path; /* order than in the info23 */ + UNISTR2 uni_home_dir; + UNISTR2 uni_dir_drive; + UNISTR2 uni_dom_controller; + UNISTR2 uni_dom_name; + DOM_SID2 dom_sid; + KRB_SID_AND_ATTR_ARRAY extra_sids; + +} PAC_LOGON_INFO; + +typedef struct pac_info_ctr +{ + union + { + PAC_LOGON_INFO *logon_info; + PAC_SIGNATURE_DATA *srv_cksum; + PAC_SIGNATURE_DATA *privsrv_cksum; + } pac; +} PAC_INFO_CTR; + +typedef struct pac_info_hdr { + uint32 type; + uint32 size; + uint32 offset; + uint32 offsethi; + PAC_INFO_CTR *ctr; +} PAC_INFO_HDR; + +typedef struct pac_data { + uint32 num_buffers; + uint32 version; + PAC_INFO_HDR *pac_info_hdr_ptr; +} PAC_DATA; + + +#endif diff --git a/source3/include/ntdomain.h b/source3/include/ntdomain.h index d02195b378..9216640c03 100644 --- a/source3/include/ntdomain.h +++ b/source3/include/ntdomain.h @@ -372,6 +372,9 @@ struct acct_info /* security descriptor structures */ #include "rpc_secdes.h" +/* pac */ +#include "authdata.h" + /* different dce/rpc pipes */ #include "rpc_lsa.h" #include "rpc_netlogon.h" @@ -382,5 +385,4 @@ struct acct_info #include "rpc_spoolss.h" #include "rpc_dfs.h" #include "rpc_ds.h" - #endif /* _NT_DOMAIN_H */ diff --git a/source3/libads/authdata.c b/source3/libads/authdata.c new file mode 100644 index 0000000000..3d25aec205 --- /dev/null +++ b/source3/libads/authdata.c @@ -0,0 +1,495 @@ +/* + Unix SMB/CIFS implementation. + kerberos authorization data (PAC) utility library + Copyright (C) Jim McDonough 2003 + + 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" + +#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); + return pac_contents; +} + +static BOOL pac_io_krb_sids(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr, + prs_struct *ps, int depth) +{ + if (NULL == sid_and_attr) + return False; + + prs_debug(ps, depth, desc, "pac_io_krb_sids"); + depth++; + + if (UNMARSHALLING(ps)) { + sid_and_attr->sid = + (DOM_SID2 * ) prs_alloc_mem(ps, sizeof(DOM_SID2)); + if (!sid_and_attr->sid) { + DEBUG(3, ("No memory available\n")); + return False; + } + } + + if(!smb_io_dom_sid2("sid", sid_and_attr->sid, ps, depth)) + return False; + + return True; +} + + +static BOOL pac_io_krb_attrs(const char *desc, KRB_SID_AND_ATTRS *sid_and_attr, + prs_struct *ps, int depth) +{ + if (NULL == sid_and_attr) + return False; + + prs_debug(ps, depth, desc, "pac_io_krb_attrs"); + depth++; + + if (!prs_uint32("sid_ptr", ps, depth, &sid_and_attr->sid_ptr)) + return False; + if (!prs_uint32("attrs", ps, depth, &sid_and_attr->attrs)) + return False; + + return True; +} + +static BOOL pac_io_krb_sid_and_attr_array(const char *desc, + KRB_SID_AND_ATTR_ARRAY *array, + uint32 num, + prs_struct *ps, int depth) +{ + int i; + + if (NULL == array) + return False; + + prs_debug(ps, depth, desc, "pac_io_krb_sid_and_attr_array"); + depth++; + + + if (!prs_uint32("count", ps, depth, &array->count)) + return False; + + if (UNMARSHALLING(ps)) { + array->krb_sid_and_attrs = (KRB_SID_AND_ATTRS *) + prs_alloc_mem(ps, sizeof(KRB_SID_AND_ATTRS) * num); + if (!array->krb_sid_and_attrs) { + DEBUG(3, ("No memory available\n")); + return False; + } + } + + for (i=0; i<num; i++) { + if (!pac_io_krb_attrs(desc, + &array->krb_sid_and_attrs[i], + ps, depth)) + return False; + + } + for (i=0; i<num; i++) { + if (!pac_io_krb_sids(desc, + &array->krb_sid_and_attrs[i], + ps, depth)) + return False; + + } + + return True; + +} + +static BOOL pac_io_pac_logon_info(const char *desc, PAC_LOGON_INFO *info, + prs_struct *ps, int depth) +{ + uint32 garbage; + if (NULL == info) + return False; + + prs_debug(ps, depth, desc, "pac_io_pac_logon_info"); + depth++; + + if (!prs_uint32("unknown", ps, depth, &garbage)) + return False; + if (!prs_uint32("unknown", ps, depth, &garbage)) + return False; + if (!prs_uint32("bufferlen", ps, depth, &garbage)) + return False; + if (!prs_uint32("bufferlenhi", ps, depth, &garbage)) + return False; + if (!prs_uint32("pointer", ps, depth, &garbage)) + 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)) + return False; + if (!smb_io_time("kickoff_time", &info->kickoff_time, ps, depth)) + return False; + if (!smb_io_time("pass_last_set_time", &info->pass_last_set_time, + ps, depth)) + return False; + if (!smb_io_time("pass_can_change_time", &info->pass_can_change_time, + ps, depth)) + return False; + if (!smb_io_time("pass_must_change_time", &info->pass_must_change_time, + ps, depth)) + return False; + + if (!smb_io_unihdr("hdr_user_name", &info->hdr_user_name, ps, depth)) + return False; + if (!smb_io_unihdr("hdr_full_name", &info->hdr_full_name, ps, depth)) + return False; + if (!smb_io_unihdr("hdr_logon_script", &info->hdr_logon_script, + ps, depth)) + return False; + if (!smb_io_unihdr("hdr_profile_path", &info->hdr_profile_path, + ps, depth)) + return False; + if (!smb_io_unihdr("hdr_home_dir", &info->hdr_home_dir, ps, depth)) + return False; + if (!smb_io_unihdr("hdr_dir_drive", &info->hdr_dir_drive, ps, depth)) + return False; + + if (!prs_uint16("logon_count", ps, depth, &info->logon_count)) + return False; + if (!prs_uint16("reserved12", ps, depth, &info->reserved12)) + return False; + if (!prs_uint32("user_rid", ps, depth, &info->user_rid)) + return False; + if (!prs_uint32("group_rid", ps, depth, &info->group_rid)) + return False; + if (!prs_uint32("group_count", ps, depth, &info->group_count)) + return False; + /* I haven't seen this contain anything yet, but when it does + we will have to make sure we decode the contents in the middle + all the unistr2s ... */ + if (!prs_uint32("group_mem_ptr", ps, depth, + &info->group_membership_ptr)) + return False; + 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])) + return False; + + if (!smb_io_unihdr("hdr_dom_controller", + &info->hdr_dom_controller, ps, depth)) + return False; + if (!smb_io_unihdr("hdr_dom_name", &info->hdr_dom_name, ps, depth)) + return False; + + /* this should be followed, but just get ptr for now */ + 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])) + return False; + + /* might be acb_info */ + if (!prs_uint32("reserved17", ps, depth, &info->reserved17)) + 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; + + if (!prs_uint32("sid_count", ps, depth, &info->sid_count)) + return False; + if (!prs_uint32("ptr_extra_sids", ps, depth, &info->ptr_extra_sids)) + return False; + if (!prs_uint32("ptr_res_group_dom_sid", ps, depth, + &info->ptr_res_group_dom_sid)) + return False; + if (!prs_uint32("res_group_count", ps, depth, &info->res_group_count)) + return False; + if (!prs_uint32("ptr_res_group_sids", ps, depth, + &info->ptr_res_group_sids)) + return False; + + if(!smb_io_unistr2("uni_user_name", &info->uni_user_name, + info->hdr_user_name.buffer, ps, depth)) + return False; + if(!smb_io_unistr2("uni_full_name", &info->uni_full_name, + info->hdr_full_name.buffer, ps, depth)) + return False; + if(!smb_io_unistr2("uni_logon_script", &info->uni_logon_script, + info->hdr_logon_script.buffer, ps, depth)) + return False; + if(!smb_io_unistr2("uni_profile_path", &info->uni_profile_path, + info->hdr_profile_path.buffer, ps, depth)) + return False; + if(!smb_io_unistr2("uni_home_dir", &info->uni_home_dir, + info->hdr_home_dir.buffer, ps, depth)) + return False; + if(!smb_io_unistr2("uni_dir_drive", &info->uni_dir_drive, + info->hdr_dir_drive.buffer, ps, depth)) + return False; + + /* the group membership list will need to be handled here */ + + if(!smb_io_unistr2("uni_dom_controller", &info->uni_dom_controller, + info->hdr_dom_controller.buffer, ps, depth)) + return False; + if(!smb_io_unistr2("uni_dom_name", &info->uni_dom_name, + info->hdr_dom_name.buffer, ps, depth)) + return False; + + if(info->ptr_dom_sid) + if(!smb_io_dom_sid2("dom_sid", &info->dom_sid, ps, depth)) + return False; + + + if (info->sid_count && info->ptr_extra_sids) { + if (!pac_io_krb_sid_and_attr_array("extra_sids", + &info->extra_sids, + info->sid_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 (!prs_uint32("type", ps, depth, &data->type)) + return False; + if (UNMARSHALLING(ps)) { + data->signature = prs_alloc_mem(ps, siglen); + if (!data->signature) { + DEBUG(3, ("No memory available\n")); + return False; + } + } + if (!prs_uint8s(False, "signature", ps, depth, data->signature,siglen)) + return False; + + return True; +} + +static BOOL pac_io_pac_info_hdr_ctr(const char *desc, PAC_INFO_HDR *hdr, + prs_struct *ps, int depth) +{ + if (NULL == hdr) + return False; + + prs_debug(ps, depth, desc, "pac_io_pac_info_hdr_ctr"); + depth++; + + if (!prs_align(ps)) + 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))); + prs_set_offset(ps, hdr->offset); + } + + if (UNMARSHALLING(ps) && hdr->size > 0) { + hdr->ctr = (PAC_INFO_CTR *) + prs_alloc_mem(ps, sizeof(PAC_INFO_CTR)); + if (!hdr->ctr) { + DEBUG(3, ("No memory available\n")); + return False; + } + } + + switch(hdr->type) { + case PAC_TYPE_LOGON_INFO: + DEBUG(5, ("PAC_TYPE_LOGON_INFO\n")); + if (UNMARSHALLING(ps)) + hdr->ctr->pac.logon_info = (PAC_LOGON_INFO *) + prs_alloc_mem(ps, sizeof(PAC_LOGON_INFO)); + if (!hdr->ctr->pac.logon_info) { + DEBUG(3, ("No memory available\n")); + return False; + } + if (!pac_io_pac_logon_info(desc, hdr->ctr->pac.logon_info, + ps, depth)) + return False; + break; + + case PAC_TYPE_SERVER_CHECKSUM: + DEBUG(5, ("PAC_TYPE_SERVER_CHECKSUM\n")); + if (UNMARSHALLING(ps)) + hdr->ctr->pac.srv_cksum = (PAC_SIGNATURE_DATA *) + prs_alloc_mem(ps, sizeof(PAC_SIGNATURE_DATA)); + if (!hdr->ctr->pac.srv_cksum) { + DEBUG(3, ("No memory available\n")); + return False; + } + if (!pac_io_pac_signature_data(desc, hdr->ctr->pac.srv_cksum, + hdr->size, ps, depth)) + return False; + break; + + case PAC_TYPE_PRIVSVR_CHECKSUM: + DEBUG(5, ("PAC_TYPE_PRIVSVR_CHECKSUM\n")); + if (UNMARSHALLING(ps)) + hdr->ctr->pac.privsrv_cksum = (PAC_SIGNATURE_DATA *) + prs_alloc_mem(ps, sizeof(PAC_SIGNATURE_DATA)); + if (!hdr->ctr->pac.privsrv_cksum) { + DEBUG(3, ("No memory available\n")); + return False; + } + if (!pac_io_pac_signature_data(desc, + hdr->ctr->pac.privsrv_cksum, + hdr->size, ps, depth)) + return False; + break; + + default: + /* dont' know, so we need to skip it */ + DEBUG(3, ("unknown PAC type %d\n", hdr->type)); + prs_set_offset(ps, prs_offset(ps) + hdr->size); + } + + return True; +} + +static BOOL pac_io_pac_info_hdr(const char *desc, PAC_INFO_HDR *hdr, + prs_struct *ps, int depth) +{ + if (NULL == hdr) + return False; + + prs_debug(ps, depth, desc, "pac_io_pac_info_hdr"); + depth++; + + if (!prs_align(ps)) + return False; + if (!prs_uint32("type", ps, depth, &hdr->type)) + return False; + if (!prs_uint32("size", ps, depth, &hdr->size)) + return False; + if (!prs_uint32("offset", ps, depth, &hdr->offset)) + return False; + if (!prs_uint32("offsethi", ps, depth, &hdr->offsethi)) + return False; + + return True; +} + +static BOOL pac_io_pac_data(const char *desc, PAC_DATA *data, + prs_struct *ps, int depth) +{ + int i; + + if (NULL == data) + return False; + + prs_debug(ps, depth, desc, "pac_io_pac_data"); + depth++; + + if (!prs_align(ps)) + return False; + if (!prs_uint32("num_buffers", ps, depth, &data->num_buffers)) + return False; + if (!prs_uint32("version", ps, depth, &data->version)) + return False; + + if (UNMARSHALLING(ps) && data->num_buffers > 0) { + if ((data->pac_info_hdr_ptr = (PAC_INFO_HDR *) + prs_alloc_mem(ps, sizeof(PAC_INFO_HDR) * + data->num_buffers)) == NULL) { + return False; + } + } + + for (i=0; i<data->num_buffers; i++) { + if (!pac_io_pac_info_hdr(desc, &data->pac_info_hdr_ptr[i], ps, + depth)) + return False; + } + + for (i=0; i<data->num_buffers; i++) { + if (!pac_io_pac_info_hdr_ctr(desc, &data->pac_info_hdr_ptr[i], + ps, depth)) + return False; + } + + return True; +} + +PAC_DATA *decode_pac_data(DATA_BLOB *auth_data, TALLOC_CTX *ctx) +{ + DATA_BLOB pac_data_blob = unwrap_pac(auth_data); + prs_struct ps; + PAC_DATA *pac_data; + + DEBUG(5,("dump_pac_data\n")); + prs_init(&ps, pac_data_blob.length, ctx, UNMARSHALL); + prs_copy_data_in(&ps, pac_data_blob.data, pac_data_blob.length); + prs_set_offset(&ps, 0); + + pac_data = (PAC_DATA *) talloc_zero(ctx, sizeof(PAC_DATA)); + pac_io_pac_data("pac data", pac_data, &ps, 0); + + prs_mem_free(&ps); + + return pac_data; +} + +#endif diff --git a/source3/libads/kerberos_verify.c b/source3/libads/kerberos_verify.c index 4d9a1bf765..56ec33b0a6 100644 --- a/source3/libads/kerberos_verify.c +++ b/source3/libads/kerberos_verify.c @@ -148,6 +148,12 @@ NTSTATUS ads_verify_ticket(ADS_STRUCT *ads, const DATA_BLOB *ticket, get_auth_data_from_tkt(auth_data, tkt); + { + TALLOC_CTX *ctx = talloc_init("pac data"); + decode_pac_data(auth_data); + talloc_destroy(ctx); + } + #if 0 if (tkt->enc_part2) { file_save("/tmp/authdata.dat", |