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 #include "mDNSFeatures.h"
18 
19 #if MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
20 
21 #include "mdns_trust.h"
22 #include "mdns_trust_checks.h"
23 #include "mdns_objects.h"
24 #include "mdns_helpers.h"
25 #include "dns_sd.h"
26 
27 #include <bsm/libbsm.h>
28 #include <CoreUtils/DebugServices.h>
29 
30 //======================================================================================================================
31 // MARK: - mdns_trust Kind Definition
32 
33 struct mdns_trust_s {
34 	struct mdns_object_s				base;					// Object base.
35 	bool								activated;				// True if the trust has been activated.
36 	bool								invalidated;			// True if the trust has bee invalidated.
37 	bool								user_activated;			// True if user called activate method.
38 	dispatch_queue_t					queue;					// Internal serial queue.
39 	dispatch_queue_t					user_queue;				// Users serial queue.
40 	mdns_trust_event_handler_t			handler;				// User's event handler.
41 	void * 								context;
42 	audit_token_t						audit_token;
43 	char *								query;
44 	mdns_trust_flags_t					flags;
45 };
46 
47 MDNS_OBJECT_SUBKIND_DEFINE(trust);
48 
49 //======================================================================================================================
50 // MARK: - mdns_trust check Public Functions
51 
52 void
mdns_trust_init(void)53 mdns_trust_init(void)
54 {
55 	mdns_trust_checks_init();
56 }
57 
58 mdns_trust_status_t
mdns_trust_check_register_service(audit_token_t audit_token,const char * _Nullable service,mdns_trust_flags_t * _Nullable flags)59 mdns_trust_check_register_service(audit_token_t audit_token, const char * _Nullable service, mdns_trust_flags_t * _Nullable flags)
60 {
61 	return mdns_trust_checks_check(&audit_token, trust_request_reg_service, NULL, service, 0, false, flags);
62 }
63 
64 mdns_trust_status_t
mdns_trust_check_bonjour(audit_token_t audit_token,const char * _Nullable service,mdns_trust_flags_t * _Nullable flags)65 mdns_trust_check_bonjour(audit_token_t audit_token, const char * _Nullable service, mdns_trust_flags_t * _Nullable flags)
66 {
67 	return mdns_trust_checks_check(&audit_token, trust_request_bonjour, NULL, service, 0, true, flags);
68 }
69 
70 mdns_trust_status_t
mdns_trust_check_query(audit_token_t audit_token,const char * qname,const char * _Nullable service,uint16_t qtype,bool force_multicast,mdns_trust_flags_t * _Nullable flags)71 mdns_trust_check_query(audit_token_t audit_token, const char * qname, const char * _Nullable service, uint16_t qtype,
72 	bool force_multicast, mdns_trust_flags_t * _Nullable flags)
73 {
74 	return mdns_trust_checks_check(&audit_token, trust_request_query, qname, service, qtype, force_multicast, flags);
75 }
76 
77 mdns_trust_status_t
mdns_trust_check_getaddrinfo(audit_token_t audit_token,const char * hostname,mdns_trust_flags_t * _Nullable flags)78 mdns_trust_check_getaddrinfo(audit_token_t audit_token, const char * hostname, mdns_trust_flags_t * _Nullable flags)
79 {
80 	return mdns_trust_checks_check(&audit_token, trust_request_query, hostname, NULL, 0, false, flags);
81 }
82 
83 //======================================================================================================================
84 // MARK: - mdns_trust Private Methods
85 
86 static void
_mdns_trust_finalize(mdns_trust_t me)87 _mdns_trust_finalize(mdns_trust_t me)
88 {
89 	dispatch_forget(&me->queue);
90 	dispatch_release_null_safe(me->user_queue);
91 	ForgetMem(&me->query);
92 	BlockForget(&me->handler);
93 }
94 
95 //======================================================================================================================
96 
97 static char *
_mdns_trust_copy_description(mdns_trust_t me,const bool debug,const bool __unused privacy)98 _mdns_trust_copy_description(mdns_trust_t me, const bool debug, const bool __unused privacy)
99 {
100 	char *				description = NULL;
101 	char				buffer[256];
102 	char *				dst = buffer;
103 	const char * const	lim = &buffer[countof(buffer)];
104 	int					n;
105 
106 	*dst = '\0';
107 	if (debug) {
108 		n = mdns_snprintf_add(&dst, lim, "<%s: %p>: ", me->base.kind->name, me);
109 		require_quiet(n >= 0, exit);
110 	}
111 	n = mdns_snprintf_add(&dst, lim, "%s ", me->base.kind->name);
112 	require_quiet(n >= 0, exit);
113 
114 	n = mdns_snprintf_add(&dst, lim, "for pid %d", audit_token_to_pid(me->audit_token));
115 	require_quiet(n >= 0, exit);
116 
117 	description = strdup(buffer);
118 
119 exit:
120 	return description;
121 }
122 
123 static void
_mdns_trust_activate_internal(mdns_trust_t me)124 _mdns_trust_activate_internal(mdns_trust_t me)
125 {
126 	mdns_retain(me);
127 	mdns_trust_checks_local_network_access_policy_update(&me->audit_token, me->queue, me->query, me->flags,
128 		^(trust_policy_state_t state) {
129 		if (!me->invalidated) {
130 			me->invalidated = true;
131 			mdns_retain(me);
132 			dispatch_async(me->user_queue,
133 			^{
134 				if (me->handler) {
135 					mdns_trust_status_t status = (state != trust_policy_state_granted) ?
136 													mdns_trust_status_denied : mdns_trust_status_granted;
137 					me->handler(mdns_trust_event_result, status);
138 				}
139 				mdns_release(me);
140 			});
141 		}
142 		mdns_release(me);
143 	});
144 }
145 
146 static void
_mdns_trust_invalidate_internal(mdns_trust_t me)147 _mdns_trust_invalidate_internal(mdns_trust_t me)
148 {
149 	require_quiet(!me->invalidated, exit);
150 	me->invalidated = true;
151 	if (me->handler) {
152 		me->handler(mdns_trust_event_invalidated, 0);
153 	}
154 exit:
155 	return;
156 }
157 
158 static void
_mdns_trust_activate_if_ready(mdns_trust_t me)159 _mdns_trust_activate_if_ready(mdns_trust_t me)
160 {
161 	if (me->user_activated && me->user_queue && !me->activated) {
162 		mdns_retain(me);
163 		dispatch_async(me->queue,
164 		^{
165 			me->activated = true;
166 			_mdns_trust_activate_internal(me);
167 			mdns_release(me);
168 		});
169 	}
170 }
171 
172 //======================================================================================================================
173 // MARK: - mdns_trust Public instance specific
174 
175 mdns_trust_t
mdns_trust_create(audit_token_t audit_token,const char * _Nullable query,mdns_trust_flags_t flags)176 mdns_trust_create(audit_token_t audit_token, const char *_Nullable query, mdns_trust_flags_t flags)
177 {
178 	mdns_trust_t op = NULL;
179 	mdns_trust_t obj 	= _mdns_trust_alloc();
180 	obj->queue			= dispatch_queue_create("trust-internal", DISPATCH_QUEUE_SERIAL);
181 	obj->audit_token	= audit_token;
182 	obj->flags			= flags;
183 	if (query != NULL) {
184 		obj->query		= strdup(query);
185 	}
186 	op					= obj;
187 	return op;
188 }
189 
190 void
mdns_trust_set_context(mdns_trust_t me,void * _Nullable context)191 mdns_trust_set_context(mdns_trust_t me, void *_Nullable context)
192 {
193 	require_quiet(me, exit);
194 	me->context = context;
195 exit:
196 	;
197 }
198 
199 void *_Nullable
mdns_trust_get_context(mdns_trust_t me)200 mdns_trust_get_context(mdns_trust_t me)
201 {
202 	require_quiet(me, exit);
203 	return me->context;
204 exit:
205 	return NULL;
206 }
207 
208 void
mdns_trust_activate(mdns_trust_t me)209 mdns_trust_activate(mdns_trust_t me)
210 {
211 	if (!me->user_activated) {
212 		me->user_activated = true;
213 		_mdns_trust_activate_if_ready(me);
214 	}
215 }
216 
217 void
mdns_trust_invalidate(mdns_trust_t me)218 mdns_trust_invalidate(mdns_trust_t me)
219 {
220 	mdns_retain(me);
221 	dispatch_async(me->queue,
222 	^{
223 		_mdns_trust_invalidate_internal(me);
224 		mdns_release(me);
225 	});
226 }
227 
228 void
mdns_trust_set_queue(mdns_trust_t me,dispatch_queue_t queue)229 mdns_trust_set_queue(mdns_trust_t me, dispatch_queue_t queue)
230 {
231 	if (!me->user_activated || !me->user_queue)
232 	{
233 		if (queue) {
234 			dispatch_retain(queue);
235 		}
236 		dispatch_release_null_safe(me->user_queue);
237 		me->user_queue = queue;
238 		_mdns_trust_activate_if_ready(me);
239 	}
240 }
241 
242 void
mdns_trust_set_event_handler(mdns_trust_t me,mdns_trust_event_handler_t handler)243 mdns_trust_set_event_handler(mdns_trust_t me, mdns_trust_event_handler_t handler)
244 {
245 	const mdns_trust_event_handler_t new_handler = handler ? Block_copy(handler) : NULL;
246 	if (me->handler) {
247 		Block_release(me->handler);
248 	}
249 	me->handler = new_handler;
250 }
251 
252 #endif // MDNSRESPONDER_SUPPORTS(APPLE, TRUST_ENFORCEMENT)
253