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