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