/* * FakeUPSPlugin.cpp * BatteryFaker * * Created by Ethan on 4/23/06. * */ #include #include #include #include #include #include #include #include #include #include #include "FakeUPSPlugin.h" extern "C" { #include #include "fakeupsServer.h" // mig generated } #define kUPSBootstrapServerName "com.apple.FakeUPS.control" #define kSysLogLevel LOG_ERR /******************************************************************************* * * Forward Declarations * ******************************************************************************/ void initMigServer(void); void mig_server_callback( CFMachPortRef port, void *msg, CFIndex size, void *info); static boolean_t pm_mig_demux( mach_msg_header_t * request, mach_msg_header_t * reply); // defined by MiG extern "C" { boolean_t fakeups_server( mach_msg_header_t *, mach_msg_header_t *); } /******************************************************************************* * _fakeups_set_properties * * mig handling call ******************************************************************************/ kern_return_t _fakeups_set_properties ( mach_port_t server, vm_offset_t properties, mach_msg_type_number_t propertiesCnt, int *return_val ) { CFTypeRef unwrapped_data = NULL; CFDictionaryRef *transmitted_properties = NULL; CFStringRef *errorResultString = NULL; unwrapped_data = IOCFUnserialize( (const char *)properties, kCFAllocatorDefault, 0, errorResultString); if( unwrapped_data ) { transmitted_properties = (CFDictionaryRef *)unwrapped_data; } else { *return_val = kIOReturnError; goto exit; } CFShow(transmitted_properties); exit: return KERN_SUCCESS; } /******************************************************************************* * initMigServer * * Registers bootstrap port for kUPSBootstrapServerName * Initializes mig receiving code, so we can receive mig * CFDictionaries of properties from BatteryFaker.app ******************************************************************************/ void initMigServer(void) { kern_return_t kern_result = 0; CFMachPortRef cf_mach_port = 0; CFRunLoopSourceRef cfmp_rls = 0; mach_port_t our_port; cf_mach_port = CFMachPortCreate(0, mig_server_callback, 0, 0); if(!cf_mach_port) { syslog(kSysLogLevel, "error error creating CFMachPort\n"); goto bail; } our_port = CFMachPortGetPort(cf_mach_port); cfmp_rls = CFMachPortCreateRunLoopSource(0, cf_mach_port, 0); if(!cfmp_rls) { syslog(kSysLogLevel, "error error no CFMachPort RunLoopSource!\n"); goto bail; } CFRunLoopAddSource(CFRunLoopGetCurrent(), cfmp_rls, kCFRunLoopDefaultMode); kern_result = bootstrap_register( bootstrap_port, kUPSBootstrapServerName, our_port); switch (kern_result) { case BOOTSTRAP_SUCCESS: syslog(kSysLogLevel, "success registering with bootstrap server\n"); break; case BOOTSTRAP_NOT_PRIVILEGED: syslog(kSysLogLevel, "pmconfigd exit: BOOTSTRAP_NOT_PRIVILIGED"); break; case BOOTSTRAP_SERVICE_ACTIVE: syslog(kSysLogLevel, "pmconfigd exit: BOOTSTRAP_SERVICE_ACTIVE"); break; default: syslog(kSysLogLevel, "pmconfigd exit: undefined mig error"); break; } bail: if(cfmp_rls) CFRelease(cfmp_rls); return; } /******************************************************************************* * pm_mig_demux * ******************************************************************************/ static boolean_t pm_mig_demux( mach_msg_header_t * request, mach_msg_header_t * reply) { boolean_t processed = FALSE; processed = fakeups_server(request, reply); if(processed) return true; // mig request is not in our subsystem range! // generate error reply packet reply->msgh_bits = MACH_MSGH_BITS( MACH_MSGH_BITS_REMOTE(request->msgh_bits), 0); reply->msgh_remote_port = request->msgh_remote_port; reply->msgh_size = sizeof(mig_reply_error_t); /* Minimal size */ reply->msgh_local_port = MACH_PORT_NULL; reply->msgh_id = request->msgh_id + 100; ((mig_reply_error_t *)reply)->NDR = NDR_record; ((mig_reply_error_t *)reply)->RetCode = MIG_BAD_ID; return processed; } /******************************************************************************* * mig_server_callback * ******************************************************************************/ __private_extern__ void mig_server_callback( CFMachPortRef port, void *msg, CFIndex size, void *info) { mig_reply_error_t * bufRequest = (mig_reply_error_t *)msg; mig_reply_error_t * bufReply = (mig_reply_error_t *) CFAllocatorAllocate( NULL, _fakeups_subsystem.maxsize, 0); mach_msg_return_t mr; int options; /* * we have a request message * pm_mig_demux actually maps this message to, * and executes, our local mig calls. */ (void) pm_mig_demux(&bufRequest->Head, &bufReply->Head); if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (bufReply->RetCode != KERN_SUCCESS)) { if (bufReply->RetCode == MIG_NO_REPLY) { /* * This return code is a little tricky -- it appears that the * demux routine found an error of some sort, but since that * error would not normally get returned either to the local * user or the remote one, we pretend it's ok. */ CFAllocatorDeallocate(NULL, bufReply); return; } /* * destroy any out-of-line data in the request buffer but don't destroy * the reply port right (since we need that to send an error message). */ bufRequest->Head.msgh_remote_port = MACH_PORT_NULL; mach_msg_destroy(&bufRequest->Head); } if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) { /* no reply port, so destroy the reply */ if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) { mach_msg_destroy(&bufReply->Head); } CFAllocatorDeallocate(NULL, bufReply); return; } /* * send reply. * * We don't want to block indefinitely because the client * isn't receiving messages from the reply port. * If we have a send-once right for the reply port, then * this isn't a concern because the send won't block. * If we have a send right, we need to use MACH_SEND_TIMEOUT. * To avoid falling off the kernel's fast RPC path unnecessarily, * we only supply MACH_SEND_TIMEOUT when absolutely necessary. */ options = MACH_SEND_MSG; if ( MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE) { options |= MACH_SEND_TIMEOUT; } mr = mach_msg(&bufReply->Head, /* msg */ options, /* option */ bufReply->Head.msgh_size, /* send_size */ 0, /* rcv_size */ MACH_PORT_NULL, /* rcv_name */ MACH_MSG_TIMEOUT_NONE, /* timeout */ MACH_PORT_NULL); /* notify */ /* Has a message error occurred? */ switch (mr) { case MACH_SEND_INVALID_DEST: case MACH_SEND_TIMED_OUT: /* the reply can't be delivered, so destroy it */ mach_msg_destroy(&bufReply->Head); break; default : /* Includes success case. */ break; } CFAllocatorDeallocate(NULL, bufReply); }