diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /auth/gensec/gensec_util.c | |
parent | Initial commit. (diff) | |
download | samba-upstream.tar.xz samba-upstream.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'auth/gensec/gensec_util.c')
-rw-r--r-- | auth/gensec/gensec_util.c | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/auth/gensec/gensec_util.c b/auth/gensec/gensec_util.c new file mode 100644 index 0000000..1075b9f --- /dev/null +++ b/auth/gensec/gensec_util.c @@ -0,0 +1,338 @@ +/* + Unix SMB/CIFS implementation. + + Generic Authentication Interface + + Copyright (C) Andrew Tridgell 2003 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006 + + 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 "includes.h" +#include "auth/gensec/gensec.h" +#include "auth/gensec/gensec_internal.h" +#include "auth/common_auth.h" +#include "../lib/util/asn1.h" +#include "param/param.h" +#include "libds/common/roles.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_AUTH + +NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx, + struct gensec_security *gensec_security, + struct smb_krb5_context *smb_krb5_context, + DATA_BLOB *pac_blob, + const char *principal_string, + const struct tsocket_address *remote_address, + struct auth_session_info **session_info) +{ + uint32_t session_info_flags = 0; + struct auth4_context *auth_context = NULL; + NTSTATUS status; + + if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) { + session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN; + } + + session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS; + + if (!pac_blob) { + enum server_role server_role = + lpcfg_server_role(gensec_security->settings->lp_ctx); + + /* + * For any domain setup (DC or member) we require having + * a PAC, as the service ticket comes from an AD DC, + * which will always provide a PAC, unless + * UF_NO_AUTH_DATA_REQUIRED is configured for our + * account, but that's just an invalid configuration, + * the admin configured for us! + * + * As a legacy case, we still allow kerberos tickets from an MIT + * realm, but only in standalone mode. In that mode we'll only + * ever accept a kerberos authentication with a keytab file + * being explicitly configured via the 'keytab method' option. + */ + if (server_role != ROLE_STANDALONE) { + DBG_WARNING("Unable to find PAC in ticket from %s, " + "failing to allow access\n", + principal_string); + return NT_STATUS_NO_IMPERSONATION_TOKEN; + } + DBG_NOTICE("Unable to find PAC for %s, resorting to local " + "user lookup\n", principal_string); + } + + auth_context = gensec_security->auth_context; + + if ((auth_context == NULL) || + (auth_context->generate_session_info_pac == NULL)) { + DBG_ERR("Cannot generate a session_info without " + "the auth_context\n"); + return NT_STATUS_INTERNAL_ERROR; + } + + status = auth_context->generate_session_info_pac( + auth_context, + mem_ctx, + smb_krb5_context, + pac_blob, + principal_string, + remote_address, + session_info_flags, + session_info); + return status; +} + +/* + magic check a GSS-API wrapper packet for an Kerberos OID +*/ +static bool gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid) +{ + bool ret = false; + struct asn1_data *data = asn1_init(NULL, ASN1_MAX_TREE_DEPTH); + + if (!data) return false; + + if (!asn1_load(data, *blob)) goto err; + if (!asn1_start_tag(data, ASN1_APPLICATION(0))) goto err; + if (!asn1_check_OID(data, oid)) goto err; + + ret = !asn1_has_error(data); + + err: + + asn1_free(data); + return ret; +} + +/** + * Check if the packet is one for the KRB5 mechansim + * + * NOTE: This is a helper that can be employed by multiple mechanisms, do + * not make assumptions about the private_data + * + * @param gensec_security GENSEC state, unused + * @param in The request, as a DATA_BLOB + * @return Error, INVALID_PARAMETER if it's not a packet for us + * or NT_STATUS_OK if the packet is ok. + */ + +NTSTATUS gensec_magic_check_krb5_oid(struct gensec_security *unused, + const DATA_BLOB *blob) +{ + if (gensec_gssapi_check_oid(blob, GENSEC_OID_KERBEROS5)) { + return NT_STATUS_OK; + } else { + return NT_STATUS_INVALID_PARAMETER; + } +} + +void gensec_child_want_feature(struct gensec_security *gensec_security, + uint32_t feature) +{ + struct gensec_security *child_security = gensec_security->child_security; + + gensec_security->want_features |= feature; + if (child_security == NULL) { + return; + } + gensec_want_feature(child_security, feature); +} + +bool gensec_child_have_feature(struct gensec_security *gensec_security, + uint32_t feature) +{ + struct gensec_security *child_security = gensec_security->child_security; + + if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) { + /* + * All mechs with sub (child) mechs need to provide DCERPC + * header signing! This is required because the negotiation + * of header signing is done before the authentication + * is completed. + */ + return true; + } + + if (child_security == NULL) { + return false; + } + + return gensec_have_feature(child_security, feature); +} + +NTSTATUS gensec_child_unseal_packet(struct gensec_security *gensec_security, + uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + const DATA_BLOB *sig) +{ + if (gensec_security->child_security == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_unseal_packet(gensec_security->child_security, + data, length, + whole_pdu, pdu_length, + sig); +} + +NTSTATUS gensec_child_check_packet(struct gensec_security *gensec_security, + const uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + const DATA_BLOB *sig) +{ + if (gensec_security->child_security == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_check_packet(gensec_security->child_security, + data, length, + whole_pdu, pdu_length, + sig); +} + +NTSTATUS gensec_child_seal_packet(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + DATA_BLOB *sig) +{ + if (gensec_security->child_security == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_seal_packet(gensec_security->child_security, + mem_ctx, + data, length, + whole_pdu, pdu_length, + sig); +} + +NTSTATUS gensec_child_sign_packet(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + DATA_BLOB *sig) +{ + if (gensec_security->child_security == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_sign_packet(gensec_security->child_security, + mem_ctx, + data, length, + whole_pdu, pdu_length, + sig); +} + +NTSTATUS gensec_child_wrap(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out) +{ + if (gensec_security->child_security == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_wrap(gensec_security->child_security, + mem_ctx, in, out); +} + +NTSTATUS gensec_child_unwrap(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out) +{ + if (gensec_security->child_security == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_unwrap(gensec_security->child_security, + mem_ctx, in, out); +} + +size_t gensec_child_sig_size(struct gensec_security *gensec_security, + size_t data_size) +{ + if (gensec_security->child_security == NULL) { + return 0; + } + + return gensec_sig_size(gensec_security->child_security, data_size); +} + +size_t gensec_child_max_input_size(struct gensec_security *gensec_security) +{ + if (gensec_security->child_security == NULL) { + return 0; + } + + return gensec_max_input_size(gensec_security->child_security); +} + +size_t gensec_child_max_wrapped_size(struct gensec_security *gensec_security) +{ + if (gensec_security->child_security == NULL) { + return 0; + } + + return gensec_max_wrapped_size(gensec_security->child_security); +} + +NTSTATUS gensec_child_session_key(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + DATA_BLOB *session_key) +{ + if (gensec_security->child_security == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_session_key(gensec_security->child_security, + mem_ctx, + session_key); +} + +NTSTATUS gensec_child_session_info(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + struct auth_session_info **session_info) +{ + if (gensec_security->child_security == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_session_info(gensec_security->child_security, + mem_ctx, + session_info); +} + +NTTIME gensec_child_expire_time(struct gensec_security *gensec_security) +{ + if (gensec_security->child_security == NULL) { + return GENSEC_EXPIRE_TIME_INFINITY; + } + + return gensec_expire_time(gensec_security->child_security); +} + +const char *gensec_child_final_auth_type(struct gensec_security *gensec_security) +{ + if (gensec_security->child_security == NULL) { + return "NONE"; + } + + return gensec_final_auth_type(gensec_security->child_security); +} |