2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * Modification History
26 * June 1, 2001 Allan Nathanson <ajn@apple.com>
27 * - public API conversion
29 * March 24, 2000 Allan Nathanson <ajn@apple.com>
33 #include <servers/bootstrap.h>
37 #include "configd_server.h"
38 #include "notify_server.h"
42 /* MiG generated externals and functions */
43 extern struct rpc_subsystem _config_subsystem
;
44 extern boolean_t
config_server(mach_msg_header_t
*, mach_msg_header_t
*);
46 /* server state information */
47 CFMachPortRef configd_port
; /* configd server port (for new session requests) */
51 config_demux(mach_msg_header_t
*request
, mach_msg_header_t
*reply
)
53 Boolean processed
= FALSE
;
54 mach_msg_format_0_trailer_t
*trailer
;
56 /* Feed the request into the ("MiG" generated) server */
58 (request
->msgh_id
>= _config_subsystem
.start
&& request
->msgh_id
< _config_subsystem
.end
)) {
59 serverSessionRef thisSession
;
61 thisSession
= getSession(request
->msgh_local_port
);
64 * Get the caller's credentials (eUID/eGID) from the message trailer.
66 trailer
= (mach_msg_security_trailer_t
*)((vm_offset_t
)request
+
67 round_msg(request
->msgh_size
));
69 if ((trailer
->msgh_trailer_type
== MACH_MSG_TRAILER_FORMAT_0
) &&
70 (trailer
->msgh_trailer_size
>= MACH_MSG_TRAILER_FORMAT_0_SIZE
)) {
71 thisSession
->callerEUID
= trailer
->msgh_sender
.val
[0];
72 thisSession
->callerEGID
= trailer
->msgh_sender
.val
[1];
73 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("caller has eUID = %d, eGID = %d"),
74 thisSession
->callerEUID
,
75 thisSession
->callerEGID
);
77 static Boolean warned
= FALSE
;
80 SCLog(_configd_verbose
, LOG_WARNING
, CFSTR("caller's credentials not available."));
83 thisSession
->callerEUID
= 0;
84 thisSession
->callerEGID
= 0;
89 * Process configd requests.
91 processed
= config_server(request
, reply
);
95 (request
->msgh_id
>= MACH_NOTIFY_FIRST
&& request
->msgh_id
< MACH_NOTIFY_LAST
)) {
96 processed
= notify_server(request
, reply
);
100 SCLog(TRUE
, LOG_ERR
, CFSTR("unknown message ID (%d) received"), request
->msgh_id
);
102 reply
->msgh_bits
= MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request
->msgh_bits
), 0);
103 reply
->msgh_remote_port
= request
->msgh_remote_port
;
104 reply
->msgh_size
= sizeof(mig_reply_error_t
); /* Minimal size */
105 reply
->msgh_local_port
= MACH_PORT_NULL
;
106 reply
->msgh_id
= request
->msgh_id
;
107 ((mig_reply_error_t
*)reply
)->NDR
= NDR_record
;
108 ((mig_reply_error_t
*)reply
)->RetCode
= MIG_BAD_ID
;
116 configdCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
118 mig_reply_error_t
*bufRequest
= msg
;
119 mig_reply_error_t
*bufReply
= CFAllocatorAllocate(NULL
, _config_subsystem
.maxsize
, 0);
120 mach_msg_return_t mr
;
123 /* we have a request message */
124 (void) config_demux(&bufRequest
->Head
, &bufReply
->Head
);
126 if (!(bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) && (bufReply
->RetCode
!= KERN_SUCCESS
)) {
128 if (bufReply
->RetCode
== MIG_NO_REPLY
) {
130 * This return code is a little tricky -- it appears that the
131 * demux routine found an error of some sort, but since that
132 * error would not normally get returned either to the local
133 * user or the remote one, we pretend it's ok.
135 CFAllocatorDeallocate(NULL
, bufReply
);
140 * destroy any out-of-line data in the request buffer but don't destroy
141 * the reply port right (since we need that to send an error message).
143 bufRequest
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
144 mach_msg_destroy(&bufRequest
->Head
);
147 if (bufReply
->Head
.msgh_remote_port
== MACH_PORT_NULL
) {
148 /* no reply port, so destroy the reply */
149 if (bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) {
150 mach_msg_destroy(&bufReply
->Head
);
152 CFAllocatorDeallocate(NULL
, bufReply
);
159 * We don't want to block indefinitely because the client
160 * isn't receiving messages from the reply port.
161 * If we have a send-once right for the reply port, then
162 * this isn't a concern because the send won't block.
163 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
164 * To avoid falling off the kernel's fast RPC path unnecessarily,
165 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
168 options
= MACH_SEND_MSG
;
169 if (MACH_MSGH_BITS_REMOTE(bufReply
->Head
.msgh_bits
) == MACH_MSG_TYPE_MOVE_SEND_ONCE
) {
170 options
|= MACH_SEND_TIMEOUT
;
172 mr
= mach_msg(&bufReply
->Head
, /* msg */
173 options
, /* option */
174 bufReply
->Head
.msgh_size
, /* send_size */
176 MACH_PORT_NULL
, /* rcv_name */
177 MACH_MSG_TIMEOUT_NONE
, /* timeout */
178 MACH_PORT_NULL
); /* notify */
181 /* Has a message error occurred? */
183 case MACH_SEND_INVALID_DEST
:
184 case MACH_SEND_TIMED_OUT
:
185 /* the reply can't be delivered, so destroy it */
186 mach_msg_destroy(&bufReply
->Head
);
190 /* Includes success case. */
194 CFAllocatorDeallocate(NULL
, bufReply
);
203 mach_port_t bootstrap_port
;
205 kern_return_t status
;
207 server_name
= getenv("SCD_SERVER");
209 server_name
= SCD_SERVER
;
212 /* Getting bootstrap server port */
213 status
= task_get_bootstrap_port(mach_task_self(), &bootstrap_port
);
214 if (status
!= KERN_SUCCESS
) {
215 fprintf(stderr
, "task_get_bootstrap_port(): %s\n",
216 mach_error_string(status
));
217 exit (EX_UNAVAILABLE
);
220 /* Check "configd" server status */
221 status
= bootstrap_status(bootstrap_port
, server_name
, &active
);
223 case BOOTSTRAP_SUCCESS
:
225 fprintf(stderr
, "configd: '%s' server already active\n",
230 case BOOTSTRAP_UNKNOWN_SERVICE
:
233 fprintf(stderr
, "bootstrap_status(): %s\n",
234 mach_error_string(status
));
235 exit (EX_UNAVAILABLE
);
244 mach_port_t bootstrap_port
;
245 CFRunLoopSourceRef rls
;
247 kern_return_t status
;
249 server_name
= getenv("SCD_SERVER");
251 server_name
= SCD_SERVER
;
254 /* Getting bootstrap server port */
255 status
= task_get_bootstrap_port(mach_task_self(), &bootstrap_port
);
256 if (status
!= KERN_SUCCESS
) {
257 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("task_get_bootstrap_port(): %s"), mach_error_string(status
));
258 exit (EX_UNAVAILABLE
);
261 /* Check "configd" server status */
262 status
= bootstrap_status(bootstrap_port
, server_name
, &active
);
264 case BOOTSTRAP_SUCCESS
:
266 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("\"%s\" is currently active, exiting."), server_name
);
267 exit (EX_UNAVAILABLE
);
270 case BOOTSTRAP_UNKNOWN_SERVICE
:
271 /* service not currently registered, "a good thing" (tm) */
274 fprintf(stderr
, "bootstrap_status(): %s\n", mach_error_string(status
));
275 exit (EX_UNAVAILABLE
);
278 /* Create the primary / new connection port */
279 configd_port
= CFMachPortCreate(NULL
, configdCallback
, NULL
, NULL
);
282 * Create and add a run loop source for the port and add this source
283 * to both the default run loop mode and the "locked" mode. These two
284 * modes will be used for normal (unlocked) communication with the
285 * server and when multiple (locked) updates are requested by a single
288 rls
= CFMachPortCreateRunLoopSource(NULL
, configd_port
, 0);
289 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
290 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, CFSTR("locked"));
293 /* Create a session for the primary / new connection port */
294 (void) addSession(configd_port
);
296 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("Registering service \"%s\""), server_name
);
297 status
= bootstrap_register(bootstrap_port
, server_name
, CFMachPortGetPort(configd_port
));
299 case BOOTSTRAP_SUCCESS
:
300 /* service not currently registered, "a good thing" (tm) */
302 case BOOTSTRAP_NOT_PRIVILEGED
:
303 SCLog(_configd_verbose
, LOG_ERR
, CFSTR("bootstrap_register(): bootstrap not privileged"));
305 case BOOTSTRAP_SERVICE_ACTIVE
:
306 SCLog(_configd_verbose
, LOG_ERR
, CFSTR("bootstrap_register(): bootstrap service active"));
309 SCLog(_configd_verbose
, LOG_ERR
, CFSTR("bootstrap_register(): %s"), mach_error_string(status
));
325 * if linked with a DEBUG version of the framework, display some
326 * debugging information
328 __showMachPortStatus();
331 * process one run loop event
333 rlMode
= (storeLocked
> 0) ? CFSTR("locked") : kCFRunLoopDefaultMode
;
334 rlStatus
= CFRunLoopRunInMode(rlMode
, 1.0e10
, TRUE
);
337 * check for, and if necessary, push out change notifications
338 * to other processes.