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