]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4:kdc: Add helper function to determine whether a device is allowed to authenticate
authorJoseph Sutton <josephsutton@catalyst.net.nz>
Thu, 15 Jun 2023 23:22:28 +0000 (11:22 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Sun, 25 Jun 2023 23:29:33 +0000 (23:29 +0000)
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/kdc/pac-glue.c
source4/kdc/pac-glue.h

index c4215974788126bfce10964b2df92838ffd45d75..b22456641953c2bbbbffb8019c5e6d0d9c8b857a 100644 (file)
@@ -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;
+}
index e96d2a5f0f72b8e8dc9cbba1f3b06cc15df54404..fa3e00331836a3b31f558d52bd1713672e8a27b1 100644 (file)
@@ -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);