1/* 2 * Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23//--------------------------------------------------------------------------- 24// Includes 25//--------------------------------------------------------------------------- 26#include <CoreFoundation/CoreFoundation.h> 27 28#include <mach/mach.h> 29#include <mach/mach_port.h> 30#include <servers/bootstrap.h> 31#include <sysexits.h> 32 33/* defined by MiG: */ 34extern struct mig_subsystem _ioupsplugin_subsystem; 35extern boolean_t ioupsplugin_server(mach_msg_header_t *, mach_msg_header_t *); 36 37int gClientUID = -1; 38 39//=========================================================================== 40// MIG Mach Messaging Routines 41//=========================================================================== 42boolean_t upsd_demux( 43 mach_msg_header_t * request, 44 mach_msg_header_t * reply) 45{ 46 boolean_t processed = FALSE; 47 48 mach_msg_format_0_trailer_t * trailer; 49 50 /* Feed the request into the ("MiG" generated) server */ 51 if (!processed && 52 (request->msgh_id >= _ioupsplugin_subsystem.start && 53 request->msgh_id < _ioupsplugin_subsystem.end)) { 54 55 /* 56 * Get the caller's credentials (eUID/eGID) from the message trailer. 57 */ 58 trailer = (mach_msg_security_trailer_t *)((vm_offset_t)request + 59 round_msg(request->msgh_size)); 60 61 if ((trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0) && 62 (trailer->msgh_trailer_size >= MACH_MSG_TRAILER_FORMAT_0_SIZE)) { 63 64 gClientUID = trailer->msgh_sender.val[0]; 65#if 0 66 //kextd_log("caller has eUID = %d, eGID = %d", 67 trailer->msgh_sender.val[0], 68 trailer->msgh_sender.val[1]); 69#endif 70 } else { 71 //kextd_error_log("caller's credentials not available"); 72 gClientUID = -1; 73 74 } 75 76 /* 77 * Process upsd requests. 78 */ 79 processed = ioupsplugin_server(request, reply); 80 } 81 82 if (!processed && 83 (request->msgh_id >= MACH_NOTIFY_FIRST && 84 request->msgh_id < MACH_NOTIFY_LAST)) { 85 86 //kextd_error_log("failed to process message"); 87 } 88 89 if (!processed) { 90 //kextd_error_log("unknown message received"); 91 } 92 93 return processed; 94} 95 96 97void upsd_mach_port_callback( 98 CFMachPortRef port, 99 void *msg, 100 CFIndex size, 101 void *info) 102{ 103 mig_reply_error_t * bufRequest = msg; 104 mig_reply_error_t * bufReply = CFAllocatorAllocate( 105 NULL, _ioupsplugin_subsystem.maxsize, 0); 106 mach_msg_return_t mr; 107 int options; 108 109 /* we have a request message */ 110 (void) upsd_demux(&bufRequest->Head, &bufReply->Head); 111 112 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && 113 (bufReply->RetCode != KERN_SUCCESS)) { 114 115 if (bufReply->RetCode == MIG_NO_REPLY) { 116 /* 117 * This return code is a little tricky -- it appears that the 118 * demux routine found an error of some sort, but since that 119 * error would not normally get returned either to the local 120 * user or the remote one, we pretend it's ok. 121 */ 122 CFAllocatorDeallocate(NULL, bufReply); 123 return; 124 } 125 126 /* 127 * destroy any out-of-line data in the request buffer but don't destroy 128 * the reply port right (since we need that to send an error message). 129 */ 130 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL; 131 mach_msg_destroy(&bufRequest->Head); 132 } 133 134 if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) { 135 /* no reply port, so destroy the reply */ 136 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 137 mach_msg_destroy(&bufReply->Head); 138 } 139 CFAllocatorDeallocate(NULL, bufReply); 140 return; 141 } 142 143 /* 144 * send reply. 145 * 146 * We don't want to block indefinitely because the client 147 * isn't receiving messages from the reply port. 148 * If we have a send-once right for the reply port, then 149 * this isn't a concern because the send won't block. 150 * If we have a send right, we need to use MACH_SEND_TIMEOUT. 151 * To avoid falling off the kernel's fast RPC path unnecessarily, 152 * we only supply MACH_SEND_TIMEOUT when absolutely necessary. 153 */ 154 155 options = MACH_SEND_MSG; 156 if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE) { 157 options |= MACH_SEND_TIMEOUT; 158 } 159 mr = mach_msg(&bufReply->Head, /* msg */ 160 options, /* option */ 161 bufReply->Head.msgh_size, /* send_size */ 162 0, /* rcv_size */ 163 MACH_PORT_NULL, /* rcv_name */ 164 MACH_MSG_TIMEOUT_NONE, /* timeout */ 165 MACH_PORT_NULL); /* notify */ 166 167 168 /* Has a message error occurred? */ 169 switch (mr) { 170 case MACH_SEND_INVALID_DEST: 171 case MACH_SEND_TIMED_OUT: 172 /* the reply can't be delivered, so destroy it */ 173 mach_msg_destroy(&bufReply->Head); 174 break; 175 176 default : 177 /* Includes success case. */ 178 break; 179 } 180 181 CFAllocatorDeallocate(NULL, bufReply); 182} 183