From: Joseph Sutton Date: Thu, 15 Jun 2023 23:22:28 +0000 (+1200) Subject: s4:kdc: Add helper function to determine whether a device is allowed to authenticate X-Git-Tag: talloc-2.4.1~210 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f857967427f78cce6ffda117e9afab572707286d;p=thirdparty%2Fsamba.git s4:kdc: Add helper function to determine whether a device is allowed to authenticate Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett --- diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index c4215974788..b2245664195 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -2735,3 +2735,158 @@ done: talloc_unlink(mem_ctx, user_info_dc); return code; } + +krb5_error_code samba_kdc_check_device(TALLOC_CTX *mem_ctx, + krb5_context context, + struct ldb_context *samdb, + struct loadparm_context *lp_ctx, + struct samba_kdc_entry *device, + const krb5_const_pac device_pac, + const bool device_pac_is_trusted, + const struct authn_kerberos_client_policy *client_policy, + struct authn_audit_info **client_audit_info_out, + NTSTATUS *status_out) +{ + TALLOC_CTX *frame = NULL; + krb5_error_code code = 0; + NTSTATUS nt_status; + struct auth_user_info_dc *device_info = NULL; + struct authn_audit_info *client_audit_info = NULL; + + if (status_out != NULL) { + *status_out = NT_STATUS_OK; + } + + if (!authn_policy_device_restrictions_present(client_policy)) { + return 0; + } + + if (device == NULL || device_pac == NULL) { + NTSTATUS out_status = NT_STATUS_INVALID_WORKSTATION; + + nt_status = authn_kerberos_client_policy_audit_info(mem_ctx, + client_policy, + NULL /* client_info */, + AUTHN_AUDIT_EVENT_KERBEROS_DEVICE_RESTRICTION, + AUTHN_AUDIT_REASON_FAST_REQUIRED, + out_status, + client_audit_info_out); + if (!NT_STATUS_IS_OK(nt_status)) { + code = KRB5KRB_ERR_GENERIC; + } else if (authn_kerberos_client_policy_is_enforced(client_policy)) { + code = KRB5KDC_ERR_POLICY; + + if (status_out != NULL) { + *status_out = out_status; + } + } else { + /* OK. */ + code = 0; + } + + goto out; + } + + frame = talloc_stackframe(); + + if (device_pac_is_trusted) { + krb5_data device_logon_info; + + enum ndr_err_code ndr_err; + DATA_BLOB device_logon_info_blob; + + union PAC_INFO pac_logon_info; + union netr_Validation validation; + + code = krb5_pac_get_buffer(context, device_pac, + PAC_TYPE_LOGON_INFO, + &device_logon_info); + if (code != 0) { + if (code == ENOENT) { + DBG_ERR("Device PAC is missing LOGON_INFO\n"); + } else { + DBG_ERR("Error getting LOGON_INFO from device PAC\n"); + } + + goto out; + } + + device_logon_info_blob = data_blob_const(device_logon_info.data, + device_logon_info.length); + + ndr_err = ndr_pull_union_blob(&device_logon_info_blob, frame, &pac_logon_info, + PAC_TYPE_LOGON_INFO, + (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO); + smb_krb5_free_data_contents(context, &device_logon_info); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + nt_status = ndr_map_error2ntstatus(ndr_err); + DBG_ERR("can't parse device PAC LOGON_INFO: %s\n", + nt_errstr(nt_status)); + + code = ndr_map_error2errno(ndr_err); + goto out; + } + + /* + * This does a bit of unnecessary work, setting up fields we + * don’t care about — we only want the SIDs. + */ + validation.sam3 = &pac_logon_info.logon_info.info->info3; + nt_status = make_user_info_dc_netlogon_validation(frame, "", 3, &validation, + true, /* This user was authenticated */ + &device_info); + if (!NT_STATUS_IS_OK(nt_status)) { + code = EINVAL; + goto out; + } + + /* + * We need to expand group memberships within our local domain, + * as the token might be generated by a trusted domain. + */ + nt_status = authsam_update_user_info_dc(frame, + samdb, + device_info); + if (!NT_STATUS_IS_OK(nt_status)) { + code = EINVAL; + goto out; + } + } else { + nt_status = samba_kdc_get_user_info_dc(frame, + device, + SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY, + SAMBA_CLAIMS_VALID_INCLUDE, + SAMBA_COMPOUNDED_AUTH_EXCLUDE, + &device_info); + if (!NT_STATUS_IS_OK(nt_status)) { + DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n", + nt_errstr(nt_status)); + + code = KRB5KDC_ERR_TGT_REVOKED; + goto out; + } + } + + nt_status = authn_policy_authenticate_from_device(frame, + samdb, + lp_ctx, + device_info, + client_policy, + &client_audit_info); + if (client_audit_info != NULL) { + *client_audit_info_out = talloc_move(mem_ctx, &client_audit_info); + } + if (!NT_STATUS_IS_OK(nt_status)) { + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED)) { + code = KRB5KDC_ERR_POLICY; + } else { + code = KRB5KRB_ERR_GENERIC; + } + + goto out; + } + +out: + talloc_free(frame); + return code; +} diff --git a/source4/kdc/pac-glue.h b/source4/kdc/pac-glue.h index e96d2a5f0f7..fa3e0033183 100644 --- a/source4/kdc/pac-glue.h +++ b/source4/kdc/pac-glue.h @@ -170,3 +170,14 @@ krb5_error_code samba_kdc_allowed_to_authenticate_to(TALLOC_CTX *mem_ctx, const struct samba_kdc_entry *server, struct authn_audit_info **server_audit_info_out, NTSTATUS *status_out); + +krb5_error_code samba_kdc_check_device(TALLOC_CTX *mem_ctx, + krb5_context context, + struct ldb_context *samdb, + struct loadparm_context *lp_ctx, + struct samba_kdc_entry *device, + krb5_const_pac device_pac, + bool device_pac_is_trusted, + const struct authn_kerberos_client_policy *client_policy, + struct authn_audit_info **client_audit_info_out, + NTSTATUS *status_out);