]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mdns_objects/mdns_trust_checks.m
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / mdns_objects / mdns_trust_checks.m
1 /*
2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #import "mDNSEmbeddedAPI.h"
18 #import "mdns_trust.h"
19 #import "mdns_trust_checks.h"
20 #import "mdns_helpers.h"
21
22 #if TARGET_OS_IOS && (TARGET_OS_EMBEDDED || TARGET_OS_SIMULATOR || !TARGET_OS_IOSMAC)
23 #define USE_IOS_LIBS 1
24 #else
25 #define USE_IOS_LIBS 0
26 #endif
27
28 #if USE_IOS_LIBS
29 #import <CoreServices/LSBundleProxy.h>
30 #import <CoreServices/LSDiskUsagePriv.h>
31 #import <CoreServices/LSApplicationRecordPriv.h>
32 #else
33 #import <CoreServices/CoreServicesPriv.h>
34 #import <Security/CodeSigning.h>
35 #endif
36
37 #import <bsm/libbsm.h>
38 #import <CoreAnalytics/CoreAnalytics.h>
39 #import <CoreUtils/DebugServices.h>
40 #import <NetworkExtension/NetworkExtensionPrivate.h>
41 #import <nw/path_evaluation.h>
42 #import <os/feature_private.h>
43 #import <xpc/private.h>
44 #import <stdatomic.h>
45
46 #define BROWSE_ALL_SERVICES_PRIVATE_ENTITLEMENT "com.apple.developer.networking.multicast"
47 #define ON_DEMAND_ENTITLEMENT "com.apple.developer.on-demand-install-capable"
48 #define TRUST_BYPASS_GAME_CENTER_SERVICE "_gamecenter._tcp"
49
50 #define kLocalDomain ((const domainname *) "\x5" "local" )
51 #define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa")
52 #define kReverseIPv4Domain ((const domainname *) "\x7" "in-addr" "\x4" "arpa")
53
54 MDNS_LOG_CATEGORY_DEFINE(trust, "trust");
55
56 //======================================================================================================================
57 // MARK: - mdns_trust_check struct
58
59 typedef struct mdns_trust_check_s {
60 trust_request_t request;
61 const char * query_name;
62 const char * service_name;
63 audit_token_t * audit_token;
64 trust_policy_state_t policy_state;
65 uint16_t request_type;
66 mdns_trust_flags_t flags;
67 bool entitlement_allowed;
68 bool force_multicast;
69 } *mdns_trust_check_t;
70
71 //======================================================================================================================
72 // MARK: - Private helpers
73
74 static void
75 _mdns_trust_post_analytic(const mdns_trust_check_t me, const LSBundleProxy * bundle_proxy,
76 const NSArray * _Nullable services)
77 {
78 AnalyticsSendEvent(@"com.apple.network.localnetwork.check",
79 @{@"bundleID" : bundle_proxy.bundleIdentifier,
80 @"entitlement" : (me->flags & mdns_trust_flags_entitlement) ? @YES : @NO,
81 @"allowed" : (me->entitlement_allowed) ? @YES : @NO,
82 @"services" : services ?: @[],
83 @"service" : [NSString stringWithUTF8String:me->service_name]});
84 }
85
86 static bool
87 _mdns_trust_checks_is_same_domain_name(const char *domain1, const char *domain2)
88 {
89 domainname d1, d2;
90 bool good = (MakeDomainNameFromDNSNameString(&d1, domain1) != NULL);
91 require_quiet(good, exit);
92
93 good = (MakeDomainNameFromDNSNameString(&d2, domain2) != NULL);
94 require_quiet(good, exit);
95
96 good = (SameDomainName(&d1, &d2) != mDNSfalse);
97
98 exit:
99 return good;
100 }
101
102 static LSBundleProxy*
103 _mdns_trust_checks_bundle_proxy_for_app(const audit_token_t *audit_token)
104 {
105 NSError *error;
106 LSBundleProxy *bundle_proxy = nil;
107
108 if (__builtin_available(macOS 10.15, ios 13.0, watchos 6.0, tvos 13.0, *)) {
109 bundle_proxy = [LSBundleProxy bundleProxyWithAuditToken:*audit_token error:&error];
110 }
111
112 return bundle_proxy;
113 }
114
115 static bool
116 _mdns_trust_checks_is_local_address(const char * _Nonnull address)
117 {
118 nw_endpoint_t endpoint = nw_endpoint_create_host(address, "0");
119 nw_path_evaluator_t evaluator = nw_path_create_evaluator_for_endpoint(endpoint, nil);
120 nw_path_t path = nw_path_evaluator_copy_path(evaluator);
121 bool local_network = nw_path_is_direct(path);
122 return (local_network != false);
123 }
124
125 static bool
126 _mdns_trust_checks_reverse_ipv6_to_ipv6_string(const domainname *name, char * _Nonnull addr_buffer,
127 socklen_t addr_buffer_len)
128 {
129 bool result = false;
130 const uint8_t * ptr;
131 int i;
132 uint8_t ipv6[16];
133
134 // If the name is of the form "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa.", where
135 // each x is a hex digit, then the sequence of 32 hex digit labels represents the nibbles of an IPv6 address in
136 // reverse order. See <https://tools.ietf.org/html/rfc3596#section-2.5>.
137
138 ptr = name->c;
139 for (i = 0; i < 32; i++)
140 {
141 unsigned int c, nibble;
142 const int j = 15 - (i / 2);
143 require_quiet(*ptr++ == 1, exit); // If this label's length is not 1, then fail.
144 c = *ptr++; // Get label byte.
145 if ( (c >= '0') && (c <= '9')) {
146 nibble = c - '0'; // If it's a hex digit, get its numeric value.
147 } else if ((c >= 'a') && (c <= 'f')) {
148 nibble = (c - 'a') + 10;
149 } else if ((c >= 'A') && (c <= 'F')) {
150 nibble = (c - 'A') + 10;
151 } else {
152 goto exit;
153 }
154 if ((i % 2) == 0) {
155 ipv6[j] = (uint8_t)nibble;
156 } else {
157 ipv6[j] |= (uint8_t)(nibble << 4);
158 }
159 }
160
161 // The rest of the name needs to be "ip6.arpa.". If it isn't, fail.
162 require_quiet(SameDomainName((const domainname *)ptr, kReverseIPv6Domain), exit);
163 (void)inet_ntop(AF_INET6, &ipv6, addr_buffer, addr_buffer_len);
164 result = true;
165 exit:
166 return result;
167 }
168
169 static bool
170 _mdns_trust_checks_reverse_ipv4_to_ipv4_string(const domainname *name, char * _Nonnull addr_buffer,
171 socklen_t addr_buffer_len)
172 {
173 bool result = false;
174 const mDNSu8 * ptr;
175 uint8_t ipv4[4];
176 uint32_t ipv4_addr;
177
178 // If the name is of the form "x.x.x.x.in-addr.arpa.", where each x is a uint8
179
180 uint8_t * dst;
181 int segments = 0;
182 bool sawDigit = 0;
183 int c, v, label_length;
184
185 ptr = name->c;
186 for (int i = 1; i <= 4; i++)
187 {
188 dst = &ipv4[4 - i];
189 *dst = 0;
190 sawDigit = false;
191 label_length = *ptr++;
192 require_quiet((label_length >= 1) && (label_length <= 3), exit);
193 for (int j = 0; j < label_length; j++) {
194 c = *ptr++; // Get label byte.
195 require_quiet((c >= '0') && (c <= '9'), exit);
196 v = (*dst * 10) + (c - '0');
197 require_quiet(v <= 255, exit);
198 *dst = (uint8_t) v;
199 if (!sawDigit) {
200 ++segments;
201 require_quiet(segments <= 4, exit);
202 sawDigit = true;
203 }
204 }
205 require_quiet(segments == i, exit);
206 }
207 require_quiet(segments == 4, exit);
208 ipv4_addr = *(uint32_t*)&ipv4; // Already in network byte order
209
210 // The rest of the name needs to be "ip-addr.arpa.". If it isn't, fail.
211 require_quiet(SameDomainName((const domainname *)ptr, kReverseIPv4Domain), exit);
212 (void)inet_ntop(AF_INET, &ipv4_addr, addr_buffer, addr_buffer_len);
213 result = true;
214 exit:
215 return result;
216 }
217
218 static bool
219 _mdns_trust_checks_should_check_query_type(const char *qname, uint16_t qtype)
220 {
221 domainname domain;
222 bool good = (MakeDomainNameFromDNSNameString(&domain, qname) != NULL);
223 require_quiet(good, exit);
224
225 bool qtype_valid = (qtype == kDNSType_PTR || qtype == kDNSQType_ANY);
226 const domainname *d = &domain;
227
228 const domainname *d1, *d2; // Top-level domain, second-level domain
229 d1 = d2 = nil;
230 while (d->c[0]) {
231 d2 = d1; d1 = d;
232 d = (const domainname*)(d->c + 1 + d->c[0]);
233 }
234
235 if (d1 && SameDomainName(d1, kLocalDomain)) {
236 return true;
237 } else if (qtype_valid && IsLocalDomain(&domain)) {
238 return true;
239 } else if (d2 && qtype_valid && SameDomainName(d2, kReverseIPv4Domain)) {
240 char str_buffer[INET_ADDRSTRLEN];
241 if (_mdns_trust_checks_reverse_ipv4_to_ipv4_string(&domain, str_buffer, sizeof(str_buffer))) {
242 if (_mdns_trust_checks_is_local_address(str_buffer)) {
243 return true;
244 }
245 }
246 } else if (d2 && qtype_valid && SameDomainName(d2, kReverseIPv6Domain)) {
247 char str_buffer[INET6_ADDRSTRLEN];
248 if (_mdns_trust_checks_reverse_ipv6_to_ipv6_string(&domain, str_buffer, sizeof(str_buffer))) {
249 if (_mdns_trust_checks_is_local_address(str_buffer)) {
250 return true;
251 }
252 }
253 }
254 exit:
255 return false;
256 }
257
258 //======================================================================================================================
259 // MARK: - mdns_trust_checks System checks
260
261 #if USE_IOS_LIBS
262
263 static bool
264 _mdns_trust_checks_system_trusted_app(const LSBundleProxy *bundle_proxy)
265 {
266 NSString * bundleid = bundle_proxy.bundleIdentifier;
267 return ([bundleid hasPrefix: @"com.apple."] != NO);
268 }
269
270 #else // !USE_IOS_LIBS
271
272 static bool
273 _mdns_trust_checks_codesigned_by_apple(const LSBundleProxy *bundle_proxy)
274 {
275 OSStatus err;
276 SecRequirementRef requirement = NULL;
277 SecStaticCodeRef code = NULL;
278
279 err = SecRequirementCreateWithString(CFSTR("anchor apple"), kSecCSDefaultFlags, &requirement);
280 require_noerr_quiet(err, exit);
281
282 err = SecStaticCodeCreateWithPath((__bridge CFURLRef)bundle_proxy.bundleURL, kSecCSDefaultFlags, &code);
283 require_noerr_quiet(err, exit);
284
285 err = SecStaticCodeCheckValidity(code, kSecCSDefaultFlags, requirement);
286
287 exit:
288 if (code) {
289 CFRelease(code);
290 }
291 if (requirement) {
292 CFRelease(requirement);
293 }
294
295 return (err == noErr);
296 }
297
298 #endif // USE_IOS_LIBS
299
300 static bool
301 _mdns_trust_checks_app_is_apple_internal(const LSBundleProxy *bundle_proxy)
302 {
303 #if USE_IOS_LIBS
304 NSString * bundleType = bundle_proxy.bundleType;
305 if ([bundleType isEqualToString:LSInternalApplicationType] ||
306 [bundleType isEqualToString:LSSystemApplicationType]) {
307 return true;
308 } else if ([bundleType isEqualToString:LSPlugInKitType] &&
309 _mdns_trust_checks_system_trusted_app(bundle_proxy)) {
310 return true;
311 } else {
312 return false;
313 }
314 #else // !USE_IOS_LIBS
315 return _mdns_trust_checks_codesigned_by_apple(bundle_proxy);
316 #endif // USE_IOS_LIBS
317 }
318
319 static bool
320 _mdns_trust_checks_app_sdk_is_minimum_version(const LSBundleProxy *bundle_proxy)
321 {
322 #if TARGET_OS_OSX
323 #define MIN_SDK_VERSION "10.16"
324 #elif TARGET_OS_WATCH
325 #define MIN_SDK_VERSION "7.0"
326 #else
327 #define MIN_SDK_VERSION "14.0"
328 #endif
329 NSString * min_vers = [NSString stringWithUTF8String:MIN_SDK_VERSION];
330 NSComparisonResult compare_result = [[bundle_proxy sdkVersion] compare:min_vers options:NSNumericSearch];
331 bool result = ((compare_result == NSOrderedSame) || (compare_result == NSOrderedDescending));
332
333 return (result != false);
334 }
335
336 //======================================================================================================================
337 // MARK: - mdns_trust_checks Policy checks
338
339 static trust_policy_state_t
340 _mdns_trust_checks_app_is_local_network_allowed(const LSBundleProxy *bundle_proxy)
341 {
342 bool denyMulticast = false;
343 bool userPrompted = false;
344 if ([NEPathController class]) {
345 NSArray<NEPathRule *> *aggregateRules = [NEPathController copyAggregatePathRules];
346 for (NEPathRule *pathRule in aggregateRules) {
347 if ([pathRule.matchSigningIdentifier isEqualToString:bundle_proxy.bundleIdentifier]) {
348 #ifdef NE_PATH_RULE_SUPPORTS_DENY_MULTICAST
349 denyMulticast = (pathRule.denyMulticast != NO);
350 #endif // NE_PATH_RULE_SUPPORTS_DENY_MULTICAST
351 #ifdef NE_PATH_RULE_SUPPORTS_MULTICAST_PREFERENCE_SET
352 userPrompted = (pathRule.multicastPreferenceSet != NO);
353 #else
354 userPrompted = true;
355 #endif // NE_PATH_RULE_SUPPORTS_MULTICAST_PREFERENCE_SET
356 break;
357 }
358 }
359 }
360
361 trust_policy_state_t state = denyMulticast ?
362 (userPrompted ? trust_policy_state_denied : trust_policy_state_pending) :
363 trust_policy_state_granted;
364 return state;
365 }
366
367 static void
368 _mdns_trust_checks_policy_check(const mdns_trust_check_t me, const LSBundleProxy *bundle_proxy)
369 {
370 me->policy_state = _mdns_trust_checks_app_is_local_network_allowed(bundle_proxy);
371 if (me->policy_state != trust_policy_state_granted) {
372 os_log_info(_mdns_trust_log(), "Local network access to %{public}s(%{private}s) policy \'%{public}s\' for (%{public}@).",
373 _mdns_trust_checks_request_to_string(me->request), me->service_name ?: me->query_name,
374 _mdns_trust_checks_policy_to_string(me->policy_state), bundle_proxy.localizedShortName);
375 }
376 }
377
378 //======================================================================================================================
379 // MARK: - mdns_trust_checks Entitlement checks
380
381 static bool
382 _mdns_trust_checks_check_on_demand_entitlement(const mdns_trust_check_t me, const LSBundleProxy *bundle_proxy)
383 {
384 // The presense of this entitlement disallows these functions
385 xpc_object_t entitlement = xpc_copy_entitlement_for_token(ON_DEMAND_ENTITLEMENT, me->audit_token);
386 if (entitlement) {
387 os_log_info(_mdns_trust_log(), "Entitlement \'%{public}s\' disallows request for (%{public}@)", ON_DEMAND_ENTITLEMENT, bundle_proxy.localizedShortName);
388 return false;
389 } else {
390 return true;
391 }
392 }
393
394 static bool
395 _mdns_trust_checks_check_browse_all_entitlement(const mdns_trust_check_t me)
396 {
397 xpc_object_t entitlement = xpc_copy_entitlement_for_token(BROWSE_ALL_SERVICES_PRIVATE_ENTITLEMENT, me->audit_token);
398 if (entitlement) {
399 bool allowed = false;
400 if (xpc_get_type(entitlement) == XPC_TYPE_BOOL) {
401 allowed = (xpc_bool_get_value(entitlement) != false);
402 }
403 return allowed;
404 } else {
405 return false;
406 }
407 }
408
409 static bool
410 _mdns_trust_checks_app_info_has_bonjour_service(const LSBundleProxy *bundle_proxy, const NSArray *services, const char * const service)
411 {
412 for (NSString * next in services) {
413 if (_mdns_trust_checks_is_same_domain_name(service, next.UTF8String)) {
414 return true;
415 }
416 }
417
418 if (_mdns_trust_checks_is_same_domain_name(service, TRUST_BYPASS_GAME_CENTER_SERVICE)) {
419 return true;
420 }
421
422 os_log_error(_mdns_trust_log(), "App Info.plist(NSBonjourServices) does not allow \'%{public}s\' for (%{public}@)", service, bundle_proxy.localizedShortName);
423 return false;
424 }
425
426 static void
427 _mdns_trust_checks_entitlement_check(const mdns_trust_check_t me, const LSBundleProxy *bundle_proxy)
428 {
429 me->entitlement_allowed = _mdns_trust_checks_check_on_demand_entitlement(me, bundle_proxy);
430 require_quiet(me->entitlement_allowed, exit);
431
432 if (os_feature_enabled(mDNSResponder, bonjour_privacy) &&
433 _mdns_trust_checks_app_sdk_is_minimum_version(bundle_proxy)) {
434 require_quiet(me->service_name, exit); // No service_name is allowed to skip entitlement checks
435 NSArray *services = nil;
436 me->entitlement_allowed = _mdns_trust_checks_check_browse_all_entitlement(me);
437 if (me->entitlement_allowed) {
438 me->flags |= mdns_trust_flags_entitlement;
439 } else {
440 // Only check if previous is false
441 services = [bundle_proxy objectForInfoDictionaryKey:@"NSBonjourServices" ofClass:[NSArray class]];
442 me->entitlement_allowed = _mdns_trust_checks_app_info_has_bonjour_service(bundle_proxy, services, me->service_name);
443 }
444 _mdns_trust_post_analytic(me, bundle_proxy, services);
445 }
446
447 exit:
448 return;
449 }
450
451 //======================================================================================================================
452 // MARK: - mdns_trust_checks Internal checks
453
454 static bool
455 _mdns_trust_checks_should_check_trust(const mdns_trust_check_t me)
456 {
457 bool should_check = true;
458
459 if (me->request == trust_request_query) {
460 should_check = (me->force_multicast || _mdns_trust_checks_should_check_query_type(me->query_name, me->request_type));
461 } else if (me->request == trust_request_reg_service) {
462 should_check = (_mdns_trust_checks_is_same_domain_name(me->service_name, TRUST_BYPASS_GAME_CENTER_SERVICE) == false);
463 }
464
465 return should_check;
466 }
467
468 static mdns_trust_status_t
469 _mdns_trust_checks_get_status(const mdns_trust_check_t me)
470 {
471 mdns_trust_status_t status;
472
473 if (me->entitlement_allowed) {
474 if (me->policy_state == trust_policy_state_granted) {
475 status = mdns_trust_status_granted;
476 } else if (me->policy_state == trust_policy_state_pending) {
477 status = mdns_trust_status_pending;
478 } else {
479 status = mdns_trust_status_denied;
480 }
481 } else {
482 status = mdns_trust_status_no_entitlement;
483 }
484 return status;
485 }
486
487 static void
488 _mdns_trust_checks_perform_all_trust_checks(const mdns_trust_check_t me)
489 {
490 LSBundleProxy *bundle_proxy = _mdns_trust_checks_bundle_proxy_for_app(me->audit_token);
491 require_quiet(bundle_proxy, exit);
492
493 bool check_more = (_mdns_trust_checks_app_is_apple_internal(bundle_proxy) == false);
494 require_quiet(check_more, exit); // Internal always allowed
495
496 _mdns_trust_checks_entitlement_check(me, bundle_proxy);
497 check_more = (me->entitlement_allowed != false);
498 require_quiet(check_more, exit); // Continue if allowed by entitlement
499
500 _mdns_trust_checks_policy_check(me, bundle_proxy); // Can interact with user so check policy last
501
502 exit:
503 return;
504 }
505
506 //======================================================================================================================
507 // MARK: - mdns_trust_checks Public functions
508
509 static _Atomic bool g_is_initialized = false;
510
511 void
512 mdns_trust_checks_init(void)
513 {
514 static dispatch_once_t s_once;
515 dispatch_once(&s_once, ^{
516 os_log_info(_mdns_trust_log(), "Initializing Launch Services -- PENDING");
517 dispatch_queue_t queue = dispatch_queue_create("com.apple.dnssd.trust.init", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
518 dispatch_async(queue, ^{
519 os_log_info(_mdns_trust_log(), "Initializing Launch Services -- START");
520 if (__builtin_available(macOS 10.16, ios 14.0, watchos 7.0, tvos 14.0, *)) {
521 // Issue a query to LaunchServices to ensure we only proceed after their database is built during migration
522 (void)[[LSApplicationRecord alloc] initWithBundleIdentifier:@"com.apple.dummy.nonexistent" allowPlaceholder:NO error:nil];
523 }
524 atomic_store(&g_is_initialized, true);
525 os_log_info(_mdns_trust_log(), "Initializing Launch Services -- COMPLETE");
526 });
527 });
528 }
529
530 void
531 mdns_trust_checks_local_network_access_policy_update(audit_token_t *audit_token, dispatch_queue_t queue,
532 const char * _Nullable query, mdns_trust_flags_t flags, _mdns_trust_checks_update_handler_t handler)
533 {
534 #ifndef NE_HAS_SHOW_LOCAL_NETWORK_ALERT_FOR_APP_EXTENDED
535 (void)query;
536 (void)flags;
537 #endif
538 @autoreleasepool {
539 LSBundleProxy *bundle_proxy = _mdns_trust_checks_bundle_proxy_for_app(audit_token);
540 __block trust_policy_state_t state = (bundle_proxy != nil) ? _mdns_trust_checks_app_is_local_network_allowed(bundle_proxy) : trust_policy_state_granted;
541 #ifdef NE_HAS_SHOW_LOCAL_NETWORK_ALERT_FOR_APP
542 if ([NEConfigurationManager class] && state == trust_policy_state_pending) {
543 os_log_info(_mdns_trust_log(), "Local network alert for (%{public}@) query(%{public}s).", bundle_proxy.localizedShortName, query ?: "local");
544 NEConfigurationManager *sharedManager = [NEConfigurationManager sharedManagerForAllUsers];
545 [sharedManager showLocalNetworkAlertForApp:bundle_proxy.bundleIdentifier
546 withCompletionQueue:queue
547 #ifdef NE_HAS_SHOW_LOCAL_NETWORK_ALERT_FOR_APP_EXTENDED
548 query:query ? [NSString stringWithUTF8String:query] : @"local"
549 hasEntitlement:(flags & mdns_trust_flags_entitlement) ? YES : NO
550 #endif
551 handler:^(BOOL allowed) {
552 state = allowed ? trust_policy_state_granted : trust_policy_state_denied;
553 os_log_info(_mdns_trust_log(), "Local network alert policy status \'%{public}s\' for (%{public}@).", _mdns_trust_checks_policy_to_string(state), bundle_proxy.localizedShortName);
554 handler(state);
555 }];
556 } else
557 #endif // HAVE_SHOW_LOCAL_NETWORK_ALERT_FOR_APP
558 {
559 if (bundle_proxy == nil) {
560 os_log_info(_mdns_trust_log(), "No bundle found for local network access policy update for PID(%d).", audit_token_to_pid(*audit_token));
561 }
562 dispatch_async(queue, ^{
563 handler(state);
564 });
565 }
566 }
567 }
568
569 mdns_trust_status_t
570 mdns_trust_checks_check(audit_token_t *audit_token, trust_request_t request, const char * _Nullable query_name,
571 const char * _Nullable service_name, uint16_t qtype, bool force_multicast, mdns_trust_flags_t * _Nullable flags)
572 {
573 struct mdns_trust_check_s ref;
574 ref.audit_token = audit_token;
575 ref.request = request;
576 ref.query_name = query_name;
577 ref.service_name = service_name;
578 ref.request_type = qtype;
579 ref.flags = mdns_trust_flags_none;
580 ref.entitlement_allowed = true; // Default allow
581 ref.force_multicast = force_multicast;
582 ref.policy_state = trust_policy_state_granted; // Default granted
583
584 require_quiet(atomic_load(&g_is_initialized), exit);
585
586 @autoreleasepool {
587 bool check_more = (_mdns_trust_checks_should_check_trust(&ref) != false);
588 require_quiet(check_more, exit);
589
590 _mdns_trust_checks_perform_all_trust_checks(&ref);
591 }
592
593 exit:
594 if (flags != nil) {
595 *flags = ref.flags;
596 }
597 return _mdns_trust_checks_get_status(&ref);
598 }