1275072Semaste/* 2275072Semaste * Copyright (c) 2000-2006 Apple Inc. All rights reserved. 3275072Semaste * 4275072Semaste * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5275072Semaste * 6275072Semaste * This file contains Original Code and/or Modifications of Original Code 7275072Semaste * as defined in and that are subject to the Apple Public Source License 8275072Semaste * Version 2.0 (the 'License'). You may not use this file except in 9275072Semaste * compliance with the License. The rights granted to you under the License 10275072Semaste * may not be used to create, or enable the creation or redistribution of, 11275072Semaste * unlawful or unlicensed copies of an Apple operating system, or to 12275072Semaste * circumvent, violate, or enable the circumvention or violation of, any 13275072Semaste * terms of an Apple operating system software license agreement. 14275072Semaste * 15275072Semaste * Please obtain a copy of the License at 16275072Semaste * http://www.opensource.apple.com/apsl/ and read it before using this file. 17275072Semaste * 18275072Semaste * The Original Code and all software distributed under the License are 19275072Semaste * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20275072Semaste * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21275072Semaste * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22275072Semaste * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23275072Semaste * Please see the License for the specific language governing rights and 24275072Semaste * limitations under the License. 25275072Semaste * 26275072Semaste * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27275072Semaste */ 28275072Semaste 29275072Semaste#include <mach/port.h> 30275072Semaste#include <mach/message.h> 31275072Semaste#include <mach/kern_return.h> 32275072Semaste#include <mach/host_priv.h> 33275072Semaste 34275072Semaste#include <kern/kern_types.h> 35275072Semaste#include <kern/kalloc.h> 36275072Semaste#include <kern/host.h> 37275072Semaste#include <kern/ipc_kobject.h> 38275072Semaste 39275072Semaste#include <ipc/ipc_port.h> 40275072Semaste 41275072Semaste#include <UserNotification/UNDTypes.h> 42275072Semaste#include <UserNotification/UNDRequest.h> 43275072Semaste#include <UserNotification/UNDReplyServer.h> 44275072Semaste#include <UserNotification/KUNCUserNotifications.h> 45275072Semaste 46275072Semaste#ifdef KERNEL_CF 47275072Semaste// external 48275072Semaste#include <IOKit/IOCFSerialize.h> 49275072Semaste#include <IOKit/IOCFUnserialize.h> 50275072Semaste#endif 51275072Semaste 52275072Semaste/* 53275072Semaste * DEFINES AND STRUCTURES 54275072Semaste */ 55275072Semaste 56275072Semastestruct UNDReply { 57275072Semaste decl_lck_mtx_data(,lock) /* UNDReply lock */ 58275072Semaste int userLandNotificationKey; 59275072Semaste KUNCUserNotificationCallBack callback; 60275072Semaste boolean_t inprogress; 61275072Semaste ipc_port_t self_port; /* Our port */ 62275072Semaste}; 63275072Semaste 64275072Semaste#define UNDReply_lock(reply) lck_mtx_lock(&reply->lock) 65275072Semaste#define UNDReply_unlock(reply) lck_mtx_lock(&reply->lock) 66275072Semaste 67275072Semaste/* forward declarations */ 68275072Semastevoid UNDReply_deallocate( 69275072Semaste UNDReplyRef reply); 70275072Semaste 71275072Semaste 72275072Semastevoid 73275072SemasteUNDReply_deallocate( 74275072Semaste UNDReplyRef reply) 75275072Semaste{ 76275072Semaste ipc_port_t port; 77275072Semaste 78275072Semaste UNDReply_lock(reply); 79275072Semaste port = reply->self_port; 80275072Semaste assert(IP_VALID(port)); 81275072Semaste ipc_kobject_set(port, IKO_NULL, IKOT_NONE); 82275072Semaste reply->self_port = IP_NULL; 83275072Semaste UNDReply_unlock(reply); 84275072Semaste 85275072Semaste ipc_port_dealloc_kernel(port); 86275072Semaste kfree(reply, sizeof(struct UNDReply)); 87275072Semaste return; 88275072Semaste} 89275072Semaste 90275072Semastestatic UNDServerRef 91275072SemasteUNDServer_reference(void) 92275072Semaste{ 93275072Semaste UNDServerRef UNDServer; 94275072Semaste kern_return_t kr; 95275072Semaste 96275072Semaste kr = host_get_user_notification_port(host_priv_self(), &UNDServer); 97275072Semaste assert(kr == KERN_SUCCESS); 98275072Semaste return UNDServer; 99275072Semaste} 100275072Semaste 101275072Semastestatic void 102275072SemasteUNDServer_deallocate( 103275072Semaste UNDServerRef UNDServer) 104275072Semaste{ 105 if (IP_VALID(UNDServer)) 106 ipc_port_release_send(UNDServer); 107} 108 109/* 110 * UND Mig Callbacks 111*/ 112 113kern_return_t 114UNDAlertCompletedWithResult_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 */ 170kern_return_t 171UNDNotificationCreated_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 192extern lck_grp_t LockCompatGroup; 193 194KUNCUserNotificationID 195KUNCGetNotificationID(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 218kern_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 233kern_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 270kern_return_t 271KUNCUserNotificationDisplayNotice( 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 301kern_return_t 302KUNCUserNotificationDisplayAlert( 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 338kern_return_t 339KUNCUserNotificationDisplayFromBundle( 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 */ 391UNDReplyRef 392convert_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 415kern_return_t 416host_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 427kern_return_t 428host_get_UNDServer( 429 host_priv_t host_priv, 430 UNDServerRef *serverp) 431{ 432 return (host_get_user_notification_port(host_priv, serverp)); 433} 434