]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
cb323159 | 2 | * Copyright (c) 2000-2019 Apple Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0a7de745 | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
0a7de745 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
2d21ac55 A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
0a7de745 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | ||
29 | #include <mach/port.h> | |
30 | #include <mach/message.h> | |
31 | #include <mach/kern_return.h> | |
91447636 | 32 | #include <mach/host_priv.h> |
1c79356b | 33 | |
91447636 A |
34 | #include <kern/kern_types.h> |
35 | #include <kern/kalloc.h> | |
1c79356b | 36 | #include <kern/host.h> |
1c79356b A |
37 | #include <kern/ipc_kobject.h> |
38 | ||
91447636 A |
39 | #include <ipc/ipc_port.h> |
40 | ||
1c79356b A |
41 | #include <UserNotification/UNDTypes.h> |
42 | #include <UserNotification/UNDRequest.h> | |
43 | #include <UserNotification/UNDReplyServer.h> | |
44 | #include <UserNotification/KUNCUserNotifications.h> | |
45 | ||
46 | #ifdef KERNEL_CF | |
47 | // external | |
48 | #include <IOKit/IOCFSerialize.h> | |
49 | #include <IOKit/IOCFUnserialize.h> | |
50 | #endif | |
51 | ||
c3c9b80d | 52 | #if CONFIG_USER_NOTIFICATION |
1c79356b A |
53 | /* |
54 | * DEFINES AND STRUCTURES | |
55 | */ | |
56 | ||
1c79356b | 57 | struct UNDReply { |
cb323159 | 58 | decl_lck_mtx_data(, lock); /* UNDReply lock */ |
0a7de745 A |
59 | int userLandNotificationKey; |
60 | KUNCUserNotificationCallBack callback; | |
61 | boolean_t inprogress; | |
62 | ipc_port_t self_port; /* Our port */ | |
1c79356b A |
63 | }; |
64 | ||
0a7de745 A |
65 | #define UNDReply_lock(reply) lck_mtx_lock(&reply->lock) |
66 | #define UNDReply_unlock(reply) lck_mtx_unlock(&reply->lock) | |
1c79356b | 67 | |
39236c6e A |
68 | extern lck_grp_t LockCompatGroup; |
69 | ||
91447636 A |
70 | /* forward declarations */ |
71 | void UNDReply_deallocate( | |
0a7de745 | 72 | UNDReplyRef reply); |
91447636 A |
73 | |
74 | ||
1c79356b A |
75 | void |
76 | UNDReply_deallocate( | |
0a7de745 | 77 | UNDReplyRef reply) |
1c79356b A |
78 | { |
79 | ipc_port_t port; | |
55e303ae | 80 | |
1c79356b A |
81 | UNDReply_lock(reply); |
82 | port = reply->self_port; | |
55e303ae | 83 | assert(IP_VALID(port)); |
1c79356b A |
84 | ipc_kobject_set(port, IKO_NULL, IKOT_NONE); |
85 | reply->self_port = IP_NULL; | |
86 | UNDReply_unlock(reply); | |
87 | ||
88 | ipc_port_dealloc_kernel(port); | |
39236c6e | 89 | lck_mtx_destroy(&reply->lock, &LockCompatGroup); |
91447636 | 90 | kfree(reply, sizeof(struct UNDReply)); |
1c79356b A |
91 | return; |
92 | } | |
93 | ||
55e303ae A |
94 | static UNDServerRef |
95 | UNDServer_reference(void) | |
96 | { | |
97 | UNDServerRef UNDServer; | |
98 | kern_return_t kr; | |
99 | ||
100 | kr = host_get_user_notification_port(host_priv_self(), &UNDServer); | |
101 | assert(kr == KERN_SUCCESS); | |
102 | return UNDServer; | |
103 | } | |
104 | ||
105 | static void | |
106 | UNDServer_deallocate( | |
0a7de745 | 107 | UNDServerRef UNDServer) |
55e303ae | 108 | { |
0a7de745 | 109 | if (IP_VALID(UNDServer)) { |
55e303ae | 110 | ipc_port_release_send(UNDServer); |
0a7de745 | 111 | } |
55e303ae A |
112 | } |
113 | ||
0a7de745 | 114 | /* |
1c79356b | 115 | * UND Mig Callbacks |
0a7de745 | 116 | */ |
1c79356b A |
117 | |
118 | kern_return_t | |
0a7de745 A |
119 | UNDAlertCompletedWithResult_rpc( |
120 | UNDReplyRef reply, | |
121 | int result, | |
122 | xmlData_t keyRef, /* raw XML bytes */ | |
2d21ac55 | 123 | #ifdef KERNEL_CF |
0a7de745 | 124 | mach_msg_type_number_t keyLen) |
2d21ac55 | 125 | #else |
0a7de745 | 126 | __unused mach_msg_type_number_t keyLen) |
2d21ac55 | 127 | #endif |
1c79356b A |
128 | { |
129 | #ifdef KERNEL_CF | |
0a7de745 A |
130 | CFStringRef xmlError = NULL; |
131 | CFDictionaryRef dict = NULL; | |
1c79356b | 132 | #else |
91447636 | 133 | const void *dict = (const void *)keyRef; |
1c79356b A |
134 | #endif |
135 | ||
0a7de745 | 136 | if (reply == UND_REPLY_NULL || !reply->inprogress) { |
1c79356b | 137 | return KERN_INVALID_ARGUMENT; |
0a7de745 | 138 | } |
1c79356b A |
139 | |
140 | /* | |
141 | * JMM - No C vesion of the Unserialize code in-kernel | |
142 | * and no C type for a CFDictionary either. For now, | |
143 | * just pass the raw keyRef through. | |
144 | */ | |
0a7de745 | 145 | #ifdef KERNEL_CF |
1c79356b A |
146 | if (keyRef && keyLen) { |
147 | dict = IOCFUnserialize(keyRef, NULL, NULL, &xmlError); | |
148 | } | |
149 | ||
150 | if (xmlError) { | |
151 | CFShow(xmlError); | |
152 | CFRelease(xmlError); | |
153 | } | |
154 | #endif /* KERNEL_CF */ | |
155 | ||
156 | if (reply->callback) { | |
b0d623f7 | 157 | (reply->callback)((int)(KUNCUserNotificationID)reply, result, dict); |
1c79356b A |
158 | } |
159 | ||
160 | UNDReply_lock(reply); | |
161 | reply->inprogress = FALSE; | |
162 | reply->userLandNotificationKey = -1; | |
163 | UNDReply_unlock(reply); | |
164 | UNDReply_deallocate(reply); | |
165 | return KERN_SUCCESS; | |
166 | } | |
167 | ||
168 | /* | |
169 | * Routine: UNDNotificationCreated_rpc | |
170 | * | |
171 | * Intermediate routine. Allows the kernel mechanism | |
172 | * to be informed that the notification request IS | |
173 | * being processed by the user-level daemon, and how | |
174 | * to identify that request. | |
175 | */ | |
176 | kern_return_t | |
0a7de745 A |
177 | UNDNotificationCreated_rpc( |
178 | UNDReplyRef reply, | |
179 | int userLandNotificationKey) | |
1c79356b | 180 | { |
0a7de745 | 181 | if (reply == UND_REPLY_NULL) { |
1c79356b | 182 | return KERN_INVALID_ARGUMENT; |
0a7de745 | 183 | } |
1c79356b A |
184 | |
185 | UNDReply_lock(reply); | |
186 | if (reply->inprogress || reply->userLandNotificationKey != -1) { | |
187 | UNDReply_unlock(reply); | |
188 | return KERN_INVALID_ARGUMENT; | |
189 | } | |
190 | reply->userLandNotificationKey = userLandNotificationKey; | |
191 | UNDReply_unlock(reply); | |
192 | return KERN_SUCCESS; | |
193 | } | |
194 | ||
195 | /* | |
196 | * KUNC Functions | |
0a7de745 | 197 | */ |
1c79356b A |
198 | |
199 | ||
200 | KUNCUserNotificationID | |
2d21ac55 | 201 | KUNCGetNotificationID(void) |
1c79356b A |
202 | { |
203 | UNDReplyRef reply; | |
204 | ||
205 | reply = (UNDReplyRef) kalloc(sizeof(struct UNDReply)); | |
206 | if (reply != UND_REPLY_NULL) { | |
cb323159 A |
207 | reply->self_port = ipc_kobject_alloc_port((ipc_kobject_t)reply, |
208 | IKOT_UND_REPLY, IPC_KOBJECT_ALLOC_NONE); | |
209 | lck_mtx_init(&reply->lock, &LockCompatGroup, LCK_ATTR_NULL); | |
210 | reply->userLandNotificationKey = -1; | |
211 | reply->inprogress = FALSE; | |
1c79356b A |
212 | } |
213 | return (KUNCUserNotificationID) reply; | |
214 | } | |
215 | ||
216 | ||
0a7de745 A |
217 | kern_return_t |
218 | KUNCExecute(char executionPath[1024], int uid, int gid) | |
1c79356b | 219 | { |
55e303ae A |
220 | UNDServerRef UNDServer; |
221 | ||
222 | UNDServer = UNDServer_reference(); | |
223 | if (IP_VALID(UNDServer)) { | |
224 | kern_return_t kr; | |
225 | kr = UNDExecute_rpc(UNDServer, executionPath, uid, gid); | |
226 | UNDServer_deallocate(UNDServer); | |
227 | return kr; | |
228 | } | |
229 | return MACH_SEND_INVALID_DEST; | |
1c79356b A |
230 | } |
231 | ||
0a7de745 A |
232 | kern_return_t |
233 | KUNCUserNotificationCancel( | |
1c79356b A |
234 | KUNCUserNotificationID id) |
235 | { | |
236 | UNDReplyRef reply = (UNDReplyRef)id; | |
237 | kern_return_t kr; | |
238 | int ulkey; | |
239 | ||
0a7de745 | 240 | if (reply == UND_REPLY_NULL) { |
1c79356b | 241 | return KERN_INVALID_ARGUMENT; |
0a7de745 | 242 | } |
1c79356b A |
243 | |
244 | UNDReply_lock(reply); | |
245 | if (!reply->inprogress) { | |
246 | UNDReply_unlock(reply); | |
247 | return KERN_INVALID_ARGUMENT; | |
248 | } | |
249 | ||
250 | reply->inprogress = FALSE; | |
91447636 | 251 | if ((ulkey = reply->userLandNotificationKey) != 0) { |
55e303ae A |
252 | UNDServerRef UNDServer; |
253 | ||
1c79356b A |
254 | reply->userLandNotificationKey = 0; |
255 | UNDReply_unlock(reply); | |
55e303ae A |
256 | |
257 | UNDServer = UNDServer_reference(); | |
258 | if (IP_VALID(UNDServer)) { | |
0a7de745 | 259 | kr = UNDCancelNotification_rpc(UNDServer, ulkey); |
55e303ae | 260 | UNDServer_deallocate(UNDServer); |
0a7de745 | 261 | } else { |
55e303ae | 262 | kr = MACH_SEND_INVALID_DEST; |
0a7de745 | 263 | } |
1c79356b A |
264 | } else { |
265 | UNDReply_unlock(reply); | |
266 | kr = KERN_SUCCESS; | |
267 | } | |
268 | UNDReply_deallocate(reply); | |
269 | return kr; | |
270 | } | |
271 | ||
272 | kern_return_t | |
273 | KUNCUserNotificationDisplayNotice( | |
0a7de745 A |
274 | int noticeTimeout, |
275 | unsigned flags, | |
276 | char *iconPath, | |
277 | char *soundPath, | |
278 | char *localizationPath, | |
279 | char *alertHeader, | |
280 | char *alertMessage, | |
281 | char *defaultButtonTitle) | |
1c79356b | 282 | { |
55e303ae A |
283 | UNDServerRef UNDServer; |
284 | ||
285 | UNDServer = UNDServer_reference(); | |
286 | if (IP_VALID(UNDServer)) { | |
287 | kern_return_t kr; | |
288 | kr = UNDDisplayNoticeSimple_rpc(UNDServer, | |
0a7de745 A |
289 | noticeTimeout, |
290 | flags, | |
291 | iconPath, | |
292 | soundPath, | |
293 | localizationPath, | |
294 | alertHeader, | |
295 | alertMessage, | |
296 | defaultButtonTitle); | |
55e303ae A |
297 | UNDServer_deallocate(UNDServer); |
298 | return kr; | |
299 | } | |
300 | return MACH_SEND_INVALID_DEST; | |
1c79356b A |
301 | } |
302 | ||
303 | kern_return_t | |
304 | KUNCUserNotificationDisplayAlert( | |
0a7de745 A |
305 | int alertTimeout, |
306 | unsigned flags, | |
307 | char *iconPath, | |
308 | char *soundPath, | |
309 | char *localizationPath, | |
310 | char *alertHeader, | |
311 | char *alertMessage, | |
312 | char *defaultButtonTitle, | |
313 | char *alternateButtonTitle, | |
314 | char *otherButtonTitle, | |
315 | unsigned *responseFlags) | |
1c79356b | 316 | { |
0a7de745 A |
317 | UNDServerRef UNDServer; |
318 | ||
55e303ae A |
319 | UNDServer = UNDServer_reference(); |
320 | if (IP_VALID(UNDServer)) { | |
0a7de745 | 321 | kern_return_t kr; |
55e303ae | 322 | kr = UNDDisplayAlertSimple_rpc(UNDServer, |
0a7de745 A |
323 | alertTimeout, |
324 | flags, | |
325 | iconPath, | |
326 | soundPath, | |
327 | localizationPath, | |
328 | alertHeader, | |
329 | alertMessage, | |
330 | defaultButtonTitle, | |
331 | alternateButtonTitle, | |
332 | otherButtonTitle, | |
333 | responseFlags); | |
55e303ae A |
334 | UNDServer_deallocate(UNDServer); |
335 | return kr; | |
336 | } | |
337 | return MACH_SEND_INVALID_DEST; | |
1c79356b A |
338 | } |
339 | ||
340 | kern_return_t | |
341 | KUNCUserNotificationDisplayFromBundle( | |
0a7de745 A |
342 | KUNCUserNotificationID id, |
343 | char *bundlePath, | |
344 | char *fileName, | |
345 | char *fileExtension, | |
346 | char *messageKey, | |
347 | char *tokenString, | |
1c79356b | 348 | KUNCUserNotificationCallBack callback, |
0a7de745 | 349 | __unused int contextKey) |
1c79356b A |
350 | { |
351 | UNDReplyRef reply = (UNDReplyRef)id; | |
55e303ae | 352 | UNDServerRef UNDServer; |
1c79356b | 353 | ipc_port_t reply_port; |
1c79356b | 354 | |
0a7de745 | 355 | if (reply == UND_REPLY_NULL) { |
1c79356b | 356 | return KERN_INVALID_ARGUMENT; |
0a7de745 | 357 | } |
1c79356b A |
358 | UNDReply_lock(reply); |
359 | if (reply->inprogress == TRUE || reply->userLandNotificationKey != -1) { | |
360 | UNDReply_unlock(reply); | |
361 | return KERN_INVALID_ARGUMENT; | |
362 | } | |
91447636 | 363 | reply->inprogress = TRUE; |
1c79356b A |
364 | reply->callback = callback; |
365 | reply_port = ipc_port_make_send(reply->self_port); | |
366 | UNDReply_unlock(reply); | |
367 | ||
55e303ae A |
368 | UNDServer = UNDServer_reference(); |
369 | if (IP_VALID(UNDServer)) { | |
370 | kern_return_t kr; | |
371 | ||
372 | kr = UNDDisplayCustomFromBundle_rpc(UNDServer, | |
0a7de745 A |
373 | reply_port, |
374 | bundlePath, | |
375 | fileName, | |
376 | fileExtension, | |
377 | messageKey, | |
378 | tokenString); | |
55e303ae A |
379 | UNDServer_deallocate(UNDServer); |
380 | return kr; | |
381 | } | |
382 | return MACH_SEND_INVALID_DEST; | |
1c79356b A |
383 | } |
384 | ||
385 | /* | |
386 | * Routine: convert_port_to_UNDReply | |
387 | * | |
388 | * MIG helper routine to convert from a mach port to a | |
389 | * UNDReply object. | |
390 | * | |
391 | * Assumptions: | |
392 | * Nothing locked. | |
393 | */ | |
394 | UNDReplyRef | |
395 | convert_port_to_UNDReply( | |
396 | ipc_port_t port) | |
397 | { | |
398 | if (IP_VALID(port)) { | |
399 | UNDReplyRef reply; | |
400 | ||
401 | ip_lock(port); | |
402 | if (!ip_active(port) || (ip_kotype(port) != IKOT_UND_REPLY)) { | |
403 | ip_unlock(port); | |
404 | return UND_REPLY_NULL; | |
405 | } | |
ea3f0419 | 406 | reply = (UNDReplyRef) ip_get_kobject(port); |
1c79356b A |
407 | assert(reply != UND_REPLY_NULL); |
408 | ip_unlock(port); | |
55e303ae | 409 | return reply; |
1c79356b A |
410 | } |
411 | return UND_REPLY_NULL; | |
412 | } | |
c3c9b80d | 413 | #endif |
1c79356b A |
414 | |
415 | /* | |
416 | * User interface for setting the host UserNotification Daemon port. | |
417 | */ | |
418 | ||
419 | kern_return_t | |
420 | host_set_UNDServer( | |
0a7de745 A |
421 | host_priv_t host_priv, |
422 | UNDServerRef server) | |
1c79356b | 423 | { |
c3c9b80d | 424 | #if CONFIG_USER_NOTIFICATION |
0a7de745 | 425 | return host_set_user_notification_port(host_priv, server); |
c3c9b80d A |
426 | #else |
427 | #pragma unused(host_priv, server) | |
428 | return KERN_NOT_SUPPORTED; | |
429 | #endif | |
1c79356b A |
430 | } |
431 | ||
432 | /* | |
433 | * User interface for retrieving the UserNotification Daemon port. | |
434 | */ | |
435 | ||
436 | kern_return_t | |
437 | host_get_UNDServer( | |
438 | host_priv_t host_priv, | |
0a7de745 | 439 | UNDServerRef *serverp) |
1c79356b | 440 | { |
c3c9b80d | 441 | #if CONFIG_USER_NOTIFICATION |
0a7de745 | 442 | return host_get_user_notification_port(host_priv, serverp); |
c3c9b80d A |
443 | #else |
444 | #pragma unused(host_priv, serverp) | |
445 | return KERN_NOT_SUPPORTED; | |
446 | #endif | |
1c79356b | 447 | } |