]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/configd_server.c
configd-53.tar.gz
[apple/configd.git] / configd.tproj / configd_server.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 /*
24 * Modification History
25 *
26 * June 1, 2001 Allan Nathanson <ajn@apple.com>
27 * - public API conversion
28 *
29 * March 24, 2000 Allan Nathanson <ajn@apple.com>
30 * - initial revision
31 */
32
33 #include <servers/bootstrap.h>
34 #include <sysexits.h>
35
36 #include "configd.h"
37 #include "configd_server.h"
38 #include "notify_server.h"
39 #include "session.h"
40 #include "notify.h"
41
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 *);
45
46 /* server state information */
47 CFMachPortRef configd_port; /* configd server port (for new session requests) */
48
49
50 boolean_t
51 config_demux(mach_msg_header_t *request, mach_msg_header_t *reply)
52 {
53 Boolean processed = FALSE;
54 mach_msg_format_0_trailer_t *trailer;
55
56 /* Feed the request into the ("MiG" generated) server */
57 if (!processed &&
58 (request->msgh_id >= _config_subsystem.start && request->msgh_id < _config_subsystem.end)) {
59 serverSessionRef thisSession;
60
61 thisSession = getSession(request->msgh_local_port);
62 if (thisSession) {
63 /*
64 * Get the caller's credentials (eUID/eGID) from the message trailer.
65 */
66 trailer = (mach_msg_security_trailer_t *)((vm_offset_t)request +
67 round_msg(request->msgh_size));
68
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);
76 } else {
77 static Boolean warned = FALSE;
78
79 if (!warned) {
80 SCLog(_configd_verbose, LOG_WARNING, CFSTR("caller's credentials not available."));
81 warned = TRUE;
82 }
83 thisSession->callerEUID = 0;
84 thisSession->callerEGID = 0;
85 }
86 }
87
88 /*
89 * Process configd requests.
90 */
91 processed = config_server(request, reply);
92 }
93
94 if (!processed &&
95 (request->msgh_id >= MACH_NOTIFY_FIRST && request->msgh_id < MACH_NOTIFY_LAST)) {
96 processed = notify_server(request, reply);
97 }
98
99 if (!processed) {
100 SCLog(TRUE, LOG_ERR, CFSTR("unknown message ID (%d) received"), request->msgh_id);
101
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;
109 }
110
111 return processed;
112 }
113
114
115 void
116 configdCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
117 {
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;
121 int options;
122
123 /* we have a request message */
124 (void) config_demux(&bufRequest->Head, &bufReply->Head);
125
126 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (bufReply->RetCode != KERN_SUCCESS)) {
127
128 if (bufReply->RetCode == MIG_NO_REPLY) {
129 /*
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.
134 */
135 CFAllocatorDeallocate(NULL, bufReply);
136 return;
137 }
138
139 /*
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).
142 */
143 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
144 mach_msg_destroy(&bufRequest->Head);
145 }
146
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);
151 }
152 CFAllocatorDeallocate(NULL, bufReply);
153 return;
154 }
155
156 /*
157 * send reply.
158 *
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.
166 */
167
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;
171 }
172 mr = mach_msg(&bufReply->Head, /* msg */
173 options, /* option */
174 bufReply->Head.msgh_size, /* send_size */
175 0, /* rcv_size */
176 MACH_PORT_NULL, /* rcv_name */
177 MACH_MSG_TIMEOUT_NONE, /* timeout */
178 MACH_PORT_NULL); /* notify */
179
180
181 /* Has a message error occurred? */
182 switch (mr) {
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);
187 break;
188
189 default :
190 /* Includes success case. */
191 break;
192 }
193
194 CFAllocatorDeallocate(NULL, bufReply);
195 return;
196 }
197
198
199 boolean_t
200 server_active()
201 {
202 boolean_t active;
203 mach_port_t bootstrap_port;
204 char *server_name;
205 kern_return_t status;
206
207 server_name = getenv("SCD_SERVER");
208 if (!server_name) {
209 server_name = SCD_SERVER;
210 }
211
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);
218 }
219
220 /* Check "configd" server status */
221 status = bootstrap_status(bootstrap_port, server_name, &active);
222 switch (status) {
223 case BOOTSTRAP_SUCCESS :
224 if (active) {
225 fprintf(stderr, "configd: '%s' server already active\n",
226 server_name);
227 return TRUE;
228 }
229 break;
230 case BOOTSTRAP_UNKNOWN_SERVICE :
231 break;
232 default :
233 fprintf(stderr, "bootstrap_status(): %s\n",
234 mach_error_string(status));
235 exit (EX_UNAVAILABLE);
236 }
237 return FALSE;
238 }
239
240 void
241 server_init()
242 {
243 boolean_t active;
244 mach_port_t bootstrap_port;
245 CFRunLoopSourceRef rls;
246 char *server_name;
247 kern_return_t status;
248
249 server_name = getenv("SCD_SERVER");
250 if (!server_name) {
251 server_name = SCD_SERVER;
252 }
253
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);
259 }
260
261 /* Check "configd" server status */
262 status = bootstrap_status(bootstrap_port, server_name, &active);
263 switch (status) {
264 case BOOTSTRAP_SUCCESS :
265 if (active) {
266 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("\"%s\" is currently active, exiting."), server_name);
267 exit (EX_UNAVAILABLE);
268 }
269 break;
270 case BOOTSTRAP_UNKNOWN_SERVICE :
271 /* service not currently registered, "a good thing" (tm) */
272 break;
273 default :
274 fprintf(stderr, "bootstrap_status(): %s\n", mach_error_string(status));
275 exit (EX_UNAVAILABLE);
276 }
277
278 /* Create the primary / new connection port */
279 configd_port = CFMachPortCreate(NULL, configdCallback, NULL, NULL);
280
281 /*
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
286 * session.
287 */
288 rls = CFMachPortCreateRunLoopSource(NULL, configd_port, 0);
289 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
290 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, CFSTR("locked"));
291 CFRelease(rls);
292
293 /* Create a session for the primary / new connection port */
294 (void) addSession(configd_port);
295
296 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("Registering service \"%s\""), server_name);
297 status = bootstrap_register(bootstrap_port, server_name, CFMachPortGetPort(configd_port));
298 switch (status) {
299 case BOOTSTRAP_SUCCESS :
300 /* service not currently registered, "a good thing" (tm) */
301 break;
302 case BOOTSTRAP_NOT_PRIVILEGED :
303 SCLog(_configd_verbose, LOG_ERR, CFSTR("bootstrap_register(): bootstrap not privileged"));
304 exit (EX_OSERR);
305 case BOOTSTRAP_SERVICE_ACTIVE :
306 SCLog(_configd_verbose, LOG_ERR, CFSTR("bootstrap_register(): bootstrap service active"));
307 exit (EX_OSERR);
308 default :
309 SCLog(_configd_verbose, LOG_ERR, CFSTR("bootstrap_register(): %s"), mach_error_string(status));
310 exit (EX_OSERR);
311 }
312
313 return;
314 }
315
316
317 void
318 server_loop()
319 {
320 CFStringRef rlMode;
321 int rlStatus;
322
323 while (TRUE) {
324 /*
325 * if linked with a DEBUG version of the framework, display some
326 * debugging information
327 */
328 __showMachPortStatus();
329
330 /*
331 * process one run loop event
332 */
333 rlMode = (storeLocked > 0) ? CFSTR("locked") : kCFRunLoopDefaultMode;
334 rlStatus = CFRunLoopRunInMode(rlMode, 1.0e10, TRUE);
335
336 /*
337 * check for, and if necessary, push out change notifications
338 * to other processes.
339 */
340 pushNotifications();
341 }
342 }