diff options
author | Stefan Metzmacher <metze@samba.org> | 2016-01-07 17:25:26 +0100 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2016-07-22 23:34:21 +0200 |
commit | c2b7bac37927d2532e1ca0ddc15780ebd5557533 (patch) | |
tree | edeca9797af836e7b11875bb262d121e2a3ce9c5 /source4/kdc | |
parent | 6762d6b5910e07aa82a3f50f5a4e6fccadc77194 (diff) | |
download | samba-c2b7bac37927d2532e1ca0ddc15780ebd5557533.tar.gz |
s4:kdc: correctly update the PAC in samba_wdc_reget_pac()
We need to keep unknown PAC elements and just copy them.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11441
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'source4/kdc')
-rw-r--r-- | source4/kdc/wdc-samba4.c | 217 |
1 files changed, 213 insertions, 4 deletions
diff --git a/source4/kdc/wdc-samba4.c b/source4/kdc/wdc-samba4.c index 6fd55df152d..7fa5d2c36dd 100644 --- a/source4/kdc/wdc-samba4.c +++ b/source4/kdc/wdc-samba4.c @@ -85,13 +85,23 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, talloc_get_type_abort(krbtgt->ctx, struct samba_kdc_entry); TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_kdc_reget_pac context"); - DATA_BLOB *pac_blob; + krb5_pac new_pac = NULL; + DATA_BLOB *pac_blob = NULL; DATA_BLOB *deleg_blob = NULL; krb5_error_code ret; NTSTATUS nt_status; struct PAC_SIGNATURE_DATA *pac_srv_sig; struct PAC_SIGNATURE_DATA *pac_kdc_sig; bool is_in_db, is_untrusted; + size_t num_types = 0; + uint32_t *types = NULL; + uint32_t forced_next_type = 0; + size_t i = 0; + ssize_t logon_info_idx = -1; + ssize_t delegation_idx = -1; + ssize_t logon_name_idx = -1; + ssize_t srv_checksum_idx = -1; + ssize_t kdc_checksum_idx = -1; if (!mem_ctx) { return ENOMEM; @@ -187,10 +197,209 @@ static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context, } } - /* We now completely regenerate this pac */ - krb5_pac_free(context, *pac); + /* Check the types of the given PAC */ + ret = krb5_pac_get_types(context, *pac, &num_types, &types); + if (ret != 0) { + talloc_free(mem_ctx); + return ret; + } - ret = samba_make_krb5_pac(context, pac_blob, deleg_blob, pac); + for (i = 0; i < num_types; i++) { + switch (types[i]) { + case PAC_TYPE_LOGON_INFO: + if (logon_info_idx != -1) { + DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n", + (int)types[i], + (int)logon_info_idx, + (int)i)); + SAFE_FREE(types); + talloc_free(mem_ctx); + return EINVAL; + } + logon_info_idx = i; + break; + case PAC_TYPE_CONSTRAINED_DELEGATION: + if (delegation_idx != -1) { + DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n", + (int)types[i], + (int)logon_info_idx, + (int)i)); + SAFE_FREE(types); + talloc_free(mem_ctx); + return EINVAL; + } + delegation_idx = i; + break; + case PAC_TYPE_LOGON_NAME: + if (logon_name_idx != -1) { + DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n", + (int)types[i], + (int)logon_info_idx, + (int)i)); + SAFE_FREE(types); + talloc_free(mem_ctx); + return EINVAL; + } + logon_name_idx = i; + break; + case PAC_TYPE_SRV_CHECKSUM: + if (srv_checksum_idx != -1) { + DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n", + (int)types[i], + (int)logon_info_idx, + (int)i)); + SAFE_FREE(types); + talloc_free(mem_ctx); + return EINVAL; + } + srv_checksum_idx = i; + break; + case PAC_TYPE_KDC_CHECKSUM: + if (kdc_checksum_idx != -1) { + DEBUG(1, ("logon type[%d] twice [%d] and [%d]: \n", + (int)types[i], + (int)logon_info_idx, + (int)i)); + SAFE_FREE(types); + talloc_free(mem_ctx); + return EINVAL; + } + kdc_checksum_idx = i; + break; + default: + continue; + } + } + + if (logon_info_idx == -1) { + DEBUG(1, ("PAC_TYPE_LOGON_INFO missing\n")); + SAFE_FREE(types); + talloc_free(mem_ctx); + return EINVAL; + } + if (logon_name_idx == -1) { + DEBUG(1, ("PAC_TYPE_LOGON_NAME missing\n")); + SAFE_FREE(types); + talloc_free(mem_ctx); + return EINVAL; + } + if (srv_checksum_idx == -1) { + DEBUG(1, ("PAC_TYPE_SRV_CHECKSUM missing\n")); + SAFE_FREE(types); + talloc_free(mem_ctx); + return EINVAL; + } + if (kdc_checksum_idx == -1) { + DEBUG(1, ("PAC_TYPE_KDC_CHECKSUM missing\n")); + SAFE_FREE(types); + talloc_free(mem_ctx); + return EINVAL; + } + + /* Build an updated PAC */ + ret = krb5_pac_init(context, &new_pac); + if (ret != 0) { + SAFE_FREE(types); + talloc_free(mem_ctx); + return ret; + } + + for (i = 0;;) { + const uint8_t zero_byte = 0; + krb5_data type_data; + DATA_BLOB type_blob = data_blob_null; + uint32_t type; + + if (forced_next_type != 0) { + /* + * We need to inject possible missing types + */ + type = forced_next_type; + forced_next_type = 0; + } else if (i < num_types) { + type = types[i]; + i++; + } else { + break; + } + + switch (type) { + case PAC_TYPE_LOGON_INFO: + type_blob = *pac_blob; + + if (delegation_idx == -1 && deleg_blob != NULL) { + /* inject CONSTRAINED_DELEGATION behind */ + forced_next_type = PAC_TYPE_CONSTRAINED_DELEGATION; + } + break; + case PAC_TYPE_CONSTRAINED_DELEGATION: + if (deleg_blob != NULL) { + type_blob = *deleg_blob; + } + break; + case PAC_TYPE_LOGON_NAME: + /* + * this is generated in the main KDC code + * we just add a place holder here. + */ + type_blob = data_blob_const(&zero_byte, 1); + break; + case PAC_TYPE_SRV_CHECKSUM: + /* + * this are generated in the main KDC code + * we just add a place holder here. + */ + type_blob = data_blob_const(&zero_byte, 1); + break; + case PAC_TYPE_KDC_CHECKSUM: + /* + * this are generated in the main KDC code + * we just add a place holders here. + */ + type_blob = data_blob_const(&zero_byte, 1); + break; + default: + /* just copy... */ + break; + } + + if (type_blob.length != 0) { + ret = krb5_copy_data_contents(&type_data, + type_blob.data, + type_blob.length); + if (ret != 0) { + SAFE_FREE(types); + krb5_pac_free(context, new_pac); + talloc_free(mem_ctx); + return ret; + } + } else { + ret = krb5_pac_get_buffer(context, *pac, + type, &type_data); + if (ret != 0) { + SAFE_FREE(types); + krb5_pac_free(context, new_pac); + talloc_free(mem_ctx); + return ret; + } + } + + ret = krb5_pac_add_buffer(context, new_pac, + type, &type_data); + kerberos_free_data_contents(context, &type_data); + if (ret != 0) { + SAFE_FREE(types); + krb5_pac_free(context, new_pac); + talloc_free(mem_ctx); + return ret; + } + } + + SAFE_FREE(types); + + /* We now replace the pac */ + krb5_pac_free(context, *pac); + *pac = new_pac; talloc_free(mem_ctx); return ret; |