diff options
author | Joseph Sutton <josephsutton@catalyst.net.nz> | 2023-05-09 11:57:09 +1200 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2023-05-18 01:03:37 +0000 |
commit | bbdb3bf8a634c32f9d2c93d6b1c77eff194dabe6 (patch) | |
tree | a6e37545dafe044dfe97c01b7c4cc5efc8c2977f /source4 | |
parent | 9a78a8b3f21c934f736870b25065278545359d21 (diff) | |
download | samba-bbdb3bf8a634c32f9d2c93d6b1c77eff194dabe6.tar.gz |
s4:kdc: Factor out PAC blob functions into new source file
pac-glue.c has become rather large, and can do without these PAC
blob–handling functions.
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'source4')
-rw-r--r-- | source4/kdc/pac-blobs.c | 250 | ||||
-rw-r--r-- | source4/kdc/pac-blobs.h | 89 | ||||
-rw-r--r-- | source4/kdc/pac-glue.c | 252 | ||||
-rw-r--r-- | source4/kdc/wscript_build | 2 |
4 files changed, 341 insertions, 252 deletions
diff --git a/source4/kdc/pac-blobs.c b/source4/kdc/pac-blobs.c new file mode 100644 index 00000000000..2c0bce6f7c6 --- /dev/null +++ b/source4/kdc/pac-blobs.c @@ -0,0 +1,250 @@ +/* + Unix SMB/CIFS implementation. + + PAC Glue between Samba and the KDC + + Copyright (C) Catalyst.Net Ltd 2023 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "source4/kdc/pac-blobs.h" + +#include "lib/util/debug.h" +#include "lib/util/samba_util.h" + +void pac_blobs_init(struct pac_blobs *pac_blobs) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(pac_blobs->type_index); ++i) { + pac_blobs->type_index[i] = SIZE_MAX; + } + + pac_blobs->type_blobs = NULL; + pac_blobs->num_types = 0; +} + +void pac_blobs_destroy(struct pac_blobs *pac_blobs) +{ + TALLOC_FREE(pac_blobs->type_blobs); +} + +static inline size_t *pac_blobs_get_index(struct pac_blobs *pac_blobs, size_t type) +{ + /* Ensure the type is valid. */ + SMB_ASSERT(type >= PAC_TYPE_BEGIN); + SMB_ASSERT(type < PAC_TYPE_END); + + return &pac_blobs->type_index[type - PAC_TYPE_BEGIN]; +} + +static inline struct type_data *pac_blobs_get(struct pac_blobs *pac_blobs, size_t type) +{ + size_t index = *pac_blobs_get_index(pac_blobs, type); + SMB_ASSERT(index < pac_blobs->num_types); + + return &pac_blobs->type_blobs[index]; +} + +krb5_error_code pac_blobs_from_krb5_pac(struct pac_blobs *pac_blobs, + TALLOC_CTX *mem_ctx, + krb5_context context, + const krb5_const_pac pac) +{ + krb5_error_code code; + uint32_t *types = NULL; + size_t i; + + code = krb5_pac_get_types(context, pac, &pac_blobs->num_types, &types); + if (code != 0) { + DBG_ERR("krb5_pac_get_types failed\n"); + return code; + } + + pac_blobs->type_blobs = talloc_array(mem_ctx, struct type_data, pac_blobs->num_types); + if (pac_blobs->type_blobs == NULL) { + DBG_ERR("Out of memory\n"); + SAFE_FREE(types); + return ENOMEM; + } + + for (i = 0; i < pac_blobs->num_types; ++i) { + uint32_t type = types[i]; + size_t *type_index = NULL; + + pac_blobs->type_blobs[i] = (struct type_data) { + .type = type, + .data = NULL, + }; + + switch (type) { + /* PAC buffer types that we support. */ + case PAC_TYPE_LOGON_INFO: + case PAC_TYPE_CREDENTIAL_INFO: + case PAC_TYPE_SRV_CHECKSUM: + case PAC_TYPE_KDC_CHECKSUM: + case PAC_TYPE_LOGON_NAME: + case PAC_TYPE_CONSTRAINED_DELEGATION: + case PAC_TYPE_UPN_DNS_INFO: + case PAC_TYPE_CLIENT_CLAIMS_INFO: + case PAC_TYPE_DEVICE_INFO: + case PAC_TYPE_DEVICE_CLAIMS_INFO: + case PAC_TYPE_TICKET_CHECKSUM: + case PAC_TYPE_ATTRIBUTES_INFO: + case PAC_TYPE_REQUESTER_SID: + case PAC_TYPE_FULL_CHECKSUM: + type_index = pac_blobs_get_index(pac_blobs, type); + if (*type_index != SIZE_MAX) { + DBG_WARNING("PAC buffer type[%"PRIu32"] twice\n", type); + pac_blobs_destroy(pac_blobs); + SAFE_FREE(types); + return EINVAL; + } + *type_index = i; + + break; + default: + break; + } + } + + SAFE_FREE(types); + return 0; +} + +krb5_error_code _pac_blobs_ensure_exists(struct pac_blobs *pac_blobs, + const uint32_t type, + const char *name, + const char *location, + const char *function) +{ + if (*pac_blobs_get_index(pac_blobs, type) == SIZE_MAX) { + DEBUGLF(DBGLVL_ERR, ("%s: %s missing\n", function, name), location, function); + return EINVAL; + } + + return 0; +} + +krb5_error_code _pac_blobs_replace_existing(struct pac_blobs *pac_blobs, + const uint32_t type, + const char *name, + const DATA_BLOB *blob, + const char *location, + const char *function) +{ + krb5_error_code code; + + code = _pac_blobs_ensure_exists(pac_blobs, + type, + name, + location, + function); + if (code != 0) { + return code; + } + + pac_blobs_get(pac_blobs, type)->data = blob; + + return 0; +} + +krb5_error_code pac_blobs_add_blob(struct pac_blobs *pac_blobs, + TALLOC_CTX *mem_ctx, + const uint32_t type, + const DATA_BLOB *blob) +{ + size_t *index = NULL; + + if (blob == NULL) { + return 0; + } + + index = pac_blobs_get_index(pac_blobs, type); + if (*index == SIZE_MAX) { + pac_blobs->type_blobs = talloc_realloc(mem_ctx, + pac_blobs->type_blobs, + struct type_data, + pac_blobs->num_types + 1); + if (pac_blobs->type_blobs == NULL) { + DBG_ERR("Out of memory\n"); + return ENOMEM; + } + + *index = pac_blobs->num_types++; + } + + *pac_blobs_get(pac_blobs, type) = (struct type_data) { + .type = type, + .data = blob, + }; + + return 0; +} + +krb5_error_code pac_blobs_remove_blob(struct pac_blobs *pac_blobs, + TALLOC_CTX *mem_ctx, + const uint32_t type) +{ + size_t found_index; + size_t i; + + /* Get the index of this PAC buffer type. */ + found_index = *pac_blobs_get_index(pac_blobs, type); + if (found_index == SIZE_MAX) { + /* We don't have a PAC buffer of this type, so we're done. */ + return 0; + } + + /* Since the PAC buffer is present, there will be at least one type in the array. */ + SMB_ASSERT(pac_blobs->num_types > 0); + + /* The index should be valid. */ + SMB_ASSERT(found_index < pac_blobs->num_types); + + /* + * Even though a consistent ordering of PAC buffers is not to be relied + * upon, we must still maintain the ordering we are given. + */ + for (i = found_index; i < pac_blobs->num_types - 1; ++i) { + size_t moved_type; + + /* Shift each following element backwards by one. */ + pac_blobs->type_blobs[i] = pac_blobs->type_blobs[i + 1]; + + /* Mark the new position of the moved element in the index. */ + moved_type = pac_blobs->type_blobs[i].type; + if (moved_type >= PAC_TYPE_BEGIN && moved_type < PAC_TYPE_END) { + *pac_blobs_get_index(pac_blobs, moved_type) = i; + } + } + + /* Mark the removed element as no longer present. */ + *pac_blobs_get_index(pac_blobs, type) = SIZE_MAX; + + /* We do not free the removed data blob, as it may be statically allocated (e.g., a null blob). */ + + /* Remove the last element from the array. */ + pac_blobs->type_blobs = talloc_realloc(mem_ctx, + pac_blobs->type_blobs, + struct type_data, + --pac_blobs->num_types); + if (pac_blobs->type_blobs == NULL) { + DBG_ERR("Out of memory\n"); + return ENOMEM; + } + + return 0; +} diff --git a/source4/kdc/pac-blobs.h b/source4/kdc/pac-blobs.h new file mode 100644 index 00000000000..769684927f3 --- /dev/null +++ b/source4/kdc/pac-blobs.h @@ -0,0 +1,89 @@ +/* + Unix SMB/CIFS implementation. + + PAC Glue between Samba and the KDC + + Copyright (C) Catalyst.Net Ltd 2023 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "lib/replace/replace.h" + +#include <stddef.h> +#include <stdint.h> + +#include "system/kerberos.h" +#include "auth/kerberos/kerberos.h" +#include <krb5/krb5.h> + +#include "lib/util/data_blob.h" +#include "librpc/gen_ndr/ndr_krb5pac.h" + +struct type_data { + uint32_t type; + const DATA_BLOB *data; +}; + +struct pac_blobs { + size_t type_index[PAC_TYPE_COUNT]; + struct type_data *type_blobs; + size_t num_types; +}; + +void pac_blobs_init(struct pac_blobs *pac_blobs); + +void pac_blobs_destroy(struct pac_blobs *pac_blobs); + +krb5_error_code pac_blobs_from_krb5_pac(struct pac_blobs *pac_blobs, + TALLOC_CTX *mem_ctx, + krb5_context context, + const krb5_const_pac pac); + +#define pac_blobs_ensure_exists(pac_blobs, type) \ + _pac_blobs_ensure_exists(pac_blobs, \ + type, \ + #type, \ + __location__, \ + __func__) + +krb5_error_code _pac_blobs_ensure_exists(struct pac_blobs *pac_blobs, + const uint32_t type, + const char *name, + const char *location, + const char *function); + +#define pac_blobs_replace_existing(pac_blobs, type, blob) \ + _pac_blobs_replace_existing(pac_blobs, \ + type, \ + #type, \ + blob, \ + __location__, \ + __func__) + +krb5_error_code _pac_blobs_replace_existing(struct pac_blobs *pac_blobs, + const uint32_t type, + const char *name, + const DATA_BLOB *blob, + const char *location, + const char *function); + +krb5_error_code pac_blobs_add_blob(struct pac_blobs *pac_blobs, + TALLOC_CTX *mem_ctx, + const uint32_t type, + const DATA_BLOB *blob); + +krb5_error_code pac_blobs_remove_blob(struct pac_blobs *pac_blobs, + TALLOC_CTX *mem_ctx, + const uint32_t type); diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index 1f94391af78..e09271bdb43 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -41,263 +41,13 @@ #include "source4/kdc/samba_kdc.h" #include "source4/kdc/pac-glue.h" #include "source4/kdc/ad_claims.h" +#include "source4/kdc/pac-blobs.h" #include <ldb.h> #undef DBGC_CLASS #define DBGC_CLASS DBGC_KERBEROS -struct type_data { - uint32_t type; - const DATA_BLOB *data; -}; - -struct pac_blobs { - size_t type_index[PAC_TYPE_COUNT]; - struct type_data *type_blobs; - size_t num_types; -}; - -static void pac_blobs_init(struct pac_blobs *pac_blobs) -{ - size_t i; - - for (i = 0; i < ARRAY_SIZE(pac_blobs->type_index); ++i) { - pac_blobs->type_index[i] = SIZE_MAX; - } - - pac_blobs->type_blobs = NULL; - pac_blobs->num_types = 0; -} - -static void pac_blobs_destroy(struct pac_blobs *pac_blobs) -{ - TALLOC_FREE(pac_blobs->type_blobs); -} - -static inline size_t *pac_blobs_get_index(struct pac_blobs *pac_blobs, size_t type) -{ - /* Ensure the type is valid. */ - SMB_ASSERT(type >= PAC_TYPE_BEGIN); - SMB_ASSERT(type < PAC_TYPE_END); - - return &pac_blobs->type_index[type - PAC_TYPE_BEGIN]; -} - -static inline struct type_data *pac_blobs_get(struct pac_blobs *pac_blobs, size_t type) -{ - size_t index = *pac_blobs_get_index(pac_blobs, type); - SMB_ASSERT(index < pac_blobs->num_types); - - return &pac_blobs->type_blobs[index]; -} - -static krb5_error_code pac_blobs_from_krb5_pac(struct pac_blobs *pac_blobs, - TALLOC_CTX *mem_ctx, - krb5_context context, - const krb5_const_pac pac) -{ - krb5_error_code code; - uint32_t *types = NULL; - size_t i; - - code = krb5_pac_get_types(context, pac, &pac_blobs->num_types, &types); - if (code != 0) { - DBG_ERR("krb5_pac_get_types failed\n"); - return code; - } - - pac_blobs->type_blobs = talloc_array(mem_ctx, struct type_data, pac_blobs->num_types); - if (pac_blobs->type_blobs == NULL) { - DBG_ERR("Out of memory\n"); - SAFE_FREE(types); - return ENOMEM; - } - - for (i = 0; i < pac_blobs->num_types; ++i) { - uint32_t type = types[i]; - size_t *type_index = NULL; - - pac_blobs->type_blobs[i] = (struct type_data) { - .type = type, - .data = NULL, - }; - - switch (type) { - /* PAC buffer types that we support. */ - case PAC_TYPE_LOGON_INFO: - case PAC_TYPE_CREDENTIAL_INFO: - case PAC_TYPE_SRV_CHECKSUM: - case PAC_TYPE_KDC_CHECKSUM: - case PAC_TYPE_LOGON_NAME: - case PAC_TYPE_CONSTRAINED_DELEGATION: - case PAC_TYPE_UPN_DNS_INFO: - case PAC_TYPE_CLIENT_CLAIMS_INFO: - case PAC_TYPE_DEVICE_INFO: - case PAC_TYPE_DEVICE_CLAIMS_INFO: - case PAC_TYPE_TICKET_CHECKSUM: - case PAC_TYPE_ATTRIBUTES_INFO: - case PAC_TYPE_REQUESTER_SID: - case PAC_TYPE_FULL_CHECKSUM: - type_index = pac_blobs_get_index(pac_blobs, type); - if (*type_index != SIZE_MAX) { - DBG_WARNING("PAC buffer type[%"PRIu32"] twice\n", type); - pac_blobs_destroy(pac_blobs); - SAFE_FREE(types); - return EINVAL; - } - *type_index = i; - - break; - default: - break; - } - } - - SAFE_FREE(types); - return 0; -} - -#define pac_blobs_ensure_exists(pac_blobs, type) \ - _pac_blobs_ensure_exists(pac_blobs, \ - type, \ - #type, \ - __location__, \ - __func__) - -static inline krb5_error_code _pac_blobs_ensure_exists(struct pac_blobs *pac_blobs, - const uint32_t type, - const char *name, - const char *location, - const char *function) -{ - if (*pac_blobs_get_index(pac_blobs, type) == SIZE_MAX) { - DEBUGLF(DBGLVL_ERR, ("%s: %s missing\n", function, name), location, function); - return EINVAL; - } - - return 0; -} - -#define pac_blobs_replace_existing(pac_blobs, type, blob) \ - _pac_blobs_replace_existing(pac_blobs, \ - type, \ - #type, \ - blob, \ - __location__, \ - __func__) - -static krb5_error_code _pac_blobs_replace_existing(struct pac_blobs *pac_blobs, - const uint32_t type, - const char *name, - const DATA_BLOB *blob, - const char *location, - const char *function) -{ - krb5_error_code code; - - code = _pac_blobs_ensure_exists(pac_blobs, - type, - name, - location, - function); - if (code != 0) { - return code; - } - - pac_blobs_get(pac_blobs, type)->data = blob; - - return 0; -} - -static krb5_error_code pac_blobs_add_blob(struct pac_blobs *pac_blobs, - TALLOC_CTX *mem_ctx, - const uint32_t type, - const DATA_BLOB *blob) -{ - size_t *index = NULL; - - if (blob == NULL) { - return 0; - } - - index = pac_blobs_get_index(pac_blobs, type); - if (*index == SIZE_MAX) { - pac_blobs->type_blobs = talloc_realloc(mem_ctx, - pac_blobs->type_blobs, - struct type_data, - pac_blobs->num_types + 1); - if (pac_blobs->type_blobs == NULL) { - DBG_ERR("Out of memory\n"); - return ENOMEM; - } - - *index = pac_blobs->num_types++; - } - - *pac_blobs_get(pac_blobs, type) = (struct type_data) { - .type = type, - .data = blob, - }; - - return 0; -} - -static krb5_error_code pac_blobs_remove_blob(struct pac_blobs *pac_blobs, - TALLOC_CTX *mem_ctx, - const uint32_t type) -{ - size_t found_index; - size_t i; - - /* Get the index of this PAC buffer type. */ - found_index = *pac_blobs_get_index(pac_blobs, type); - if (found_index == SIZE_MAX) { - /* We don't have a PAC buffer of this type, so we're done. */ - return 0; - } - - /* Since the PAC buffer is present, there will be at least one type in the array. */ - SMB_ASSERT(pac_blobs->num_types > 0); - - /* The index should be valid. */ - SMB_ASSERT(found_index < pac_blobs->num_types); - - /* - * Even though a consistent ordering of PAC buffers is not to be relied - * upon, we must still maintain the ordering we are given. - */ - for (i = found_index; i < pac_blobs->num_types - 1; ++i) { - size_t moved_type; - - /* Shift each following element backwards by one. */ - pac_blobs->type_blobs[i] = pac_blobs->type_blobs[i + 1]; - - /* Mark the new position of the moved element in the index. */ - moved_type = pac_blobs->type_blobs[i].type; - if (moved_type >= PAC_TYPE_BEGIN && moved_type < PAC_TYPE_END) { - *pac_blobs_get_index(pac_blobs, moved_type) = i; - } - } - - /* Mark the removed element as no longer present. */ - *pac_blobs_get_index(pac_blobs, type) = SIZE_MAX; - - /* We do not free the removed data blob, as it may be statically allocated (e.g., a null blob). */ - - /* Remove the last element from the array. */ - pac_blobs->type_blobs = talloc_realloc(mem_ctx, - pac_blobs->type_blobs, - struct type_data, - --pac_blobs->num_types); - if (pac_blobs->type_blobs == NULL) { - DBG_ERR("Out of memory\n"); - return ENOMEM; - } - - return 0; -} - static NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx, const struct auth_user_info_dc *info, diff --git a/source4/kdc/wscript_build b/source4/kdc/wscript_build index c6c00c4c369..807fd10791c 100644 --- a/source4/kdc/wscript_build +++ b/source4/kdc/wscript_build @@ -122,7 +122,7 @@ bld.SAMBA_SUBSYSTEM('sdb_kdb', ) bld.SAMBA_SUBSYSTEM('PAC_GLUE', - source='pac-glue.c', + source='pac-glue.c pac-blobs.c', deps='ldb auth4_sam common_auth samba-credentials samba-hostconfig com_err ad_claims' ) |