2 * Copyright (c) 2000-2011, 2013, 2015-2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * March 9, 2004 Allan Nathanson <ajn@apple.com>
28 * - add DNS configuration server
30 * June 1, 2001 Allan Nathanson <ajn@apple.com>
31 * - public API conversion
33 * March 24, 2000 Allan Nathanson <ajn@apple.com>
37 #include <TargetConditionals.h>
40 #include <sys/types.h>
41 #include <servers/bootstrap.h>
44 #include "configd_server.h"
45 #include "notify_server.h"
48 /* MiG generated externals and functions */
49 extern struct mig_subsystem _config_subsystem
;
50 extern boolean_t
config_server(mach_msg_header_t
*, mach_msg_header_t
*);
52 /* configd server port (for new session requests) */
53 static CFMachPortRef configd_port
= NULL
;
58 config_demux(mach_msg_header_t
*request
, mach_msg_header_t
*reply
)
60 Boolean processed
= FALSE
;
63 * (attempt to) process SCDynamicStore requests.
65 processed
= config_server(request
, reply
);
71 * (attempt to) process (NO MORE SENDERS) notification messages.
73 processed
= notify_server(request
, reply
);
79 * unknown message ID, log and return an error.
81 SC_log(LOG_ERR
, "unknown message ID (%d) received", request
->msgh_id
);
82 reply
->msgh_bits
= MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request
->msgh_bits
), 0);
83 reply
->msgh_remote_port
= request
->msgh_remote_port
;
84 reply
->msgh_size
= sizeof(mig_reply_error_t
); /* Minimal size */
85 reply
->msgh_local_port
= MACH_PORT_NULL
;
86 reply
->msgh_id
= request
->msgh_id
+ 100;
87 ((mig_reply_error_t
*)reply
)->NDR
= NDR_record
;
88 ((mig_reply_error_t
*)reply
)->RetCode
= MIG_BAD_ID
;
94 #define MACH_MSG_BUFFER_SIZE 128
99 configdCallback(CFMachPortRef port
, void *msg
, CFIndex size
, void *info
)
104 mig_reply_error_t
* bufRequest
= msg
;
105 uint32_t bufReply_q
[MACH_MSG_BUFFER_SIZE
/sizeof(uint32_t)];
106 mig_reply_error_t
* bufReply
= (mig_reply_error_t
*)bufReply_q
;
107 static size_t bufSize
= 0;
108 mach_msg_return_t mr
;
112 // get max size for MiG reply buffers
113 bufSize
= _config_subsystem
.maxsize
;
115 // check if our on-the-stack reply buffer will be big enough
116 if (bufSize
> sizeof(bufReply_q
)) {
117 SC_log(LOG_NOTICE
, "buffer size should be increased > %d",
118 _config_subsystem
.maxsize
);
122 if (bufSize
> sizeof(bufReply_q
)) {
123 bufReply
= CFAllocatorAllocate(NULL
, _config_subsystem
.maxsize
, 0);
125 bufReply
->RetCode
= 0;
127 /* we have a request message */
128 (void) config_demux(&bufRequest
->Head
, &bufReply
->Head
);
130 if (!(bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)) {
131 if (bufReply
->RetCode
== MIG_NO_REPLY
) {
132 bufReply
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
133 } else if ((bufReply
->RetCode
!= KERN_SUCCESS
) &&
134 (bufRequest
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
)) {
136 * destroy the request - but not the reply port
138 bufRequest
->Head
.msgh_remote_port
= MACH_PORT_NULL
;
139 mach_msg_destroy(&bufRequest
->Head
);
143 if (bufReply
->Head
.msgh_remote_port
!= MACH_PORT_NULL
) {
147 * We don't want to block indefinitely because the client
148 * isn't receiving messages from the reply port.
149 * If we have a send-once right for the reply port, then
150 * this isn't a concern because the send won't block.
151 * If we have a send right, we need to use MACH_SEND_TIMEOUT.
152 * To avoid falling off the kernel's fast RPC path unnecessarily,
153 * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
156 options
= MACH_SEND_MSG
;
157 if (MACH_MSGH_BITS_REMOTE(bufReply
->Head
.msgh_bits
) != MACH_MSG_TYPE_MOVE_SEND_ONCE
) {
158 options
|= MACH_SEND_TIMEOUT
;
160 mr
= mach_msg(&bufReply
->Head
, /* msg */
161 options
, /* option */
162 bufReply
->Head
.msgh_size
, /* send_size */
164 MACH_PORT_NULL
, /* rcv_name */
165 MACH_MSG_TIMEOUT_NONE
, /* timeout */
166 MACH_PORT_NULL
); /* notify */
168 /* Has a message error occurred? */
170 case MACH_SEND_INVALID_DEST
:
171 case MACH_SEND_TIMED_OUT
:
174 /* Includes success case. */
179 if (bufReply
->Head
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) {
180 mach_msg_destroy(&bufReply
->Head
);
185 if (bufReply
!= (mig_reply_error_t
*)bufReply_q
)
186 CFAllocatorDeallocate(NULL
, bufReply
);
193 serverMPCopyDescription(const void *info
)
196 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<main DynamicStore MP>"));
204 serverSessionRef mySession
;
206 CFRunLoopSourceRef rls
;
208 mach_port_t service_port
= MACH_PORT_NULL
;
209 kern_return_t status
;
211 service_name
= getenv("SCD_SERVER");
212 if (service_name
== NULL
) {
213 service_name
= SCD_SERVER
;
216 /* Check "configd" server status */
217 status
= bootstrap_check_in(bootstrap_port
, service_name
, &service_port
);
219 case BOOTSTRAP_SUCCESS
:
220 /* if we are being [re-]started by launchd */
222 case BOOTSTRAP_NOT_PRIVILEGED
:
223 /* if another instance of the server is starting */
224 SC_log(LOG_ERR
, "'%s' server already starting", service_name
);
225 exit (EX_UNAVAILABLE
);
226 case BOOTSTRAP_SERVICE_ACTIVE
:
227 /* if another instance of the server is active */
228 SC_log(LOG_ERR
, "'%s' server already active", service_name
);
229 exit (EX_UNAVAILABLE
);
231 SC_log(LOG_ERR
, "server_init bootstrap_check_in(..., '%s', ...) failed: %s",
233 bootstrap_strerror(status
));
234 exit (EX_UNAVAILABLE
);
237 /* Create the primary / new connection port and backing session */
238 mySession
= addSession(service_port
, serverMPCopyDescription
);
239 configd_port
= mySession
->serverPort
;
242 * Create and add a run loop source for the port and add this source
243 * to the default run loop mode.
245 rls
= CFMachPortCreateRunLoopSource(NULL
, configd_port
, 0);
246 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
249 // bump thread QoS priority
250 ret
= pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED
, 0);
252 SC_log(LOG_ERR
, "pthread_set_qos_class_self_np() failed: %s", strerror(errno
));
263 if (configd_port
!= NULL
) {
264 mach_port_t service_port
= CFMachPortGetPort(configd_port
);
266 CFMachPortInvalidate(configd_port
);
267 CFRelease(configd_port
);
270 if (service_port
!= MACH_PORT_NULL
) {
271 (void) mach_port_mod_refs(mach_task_self(),
273 MACH_PORT_RIGHT_RECEIVE
,
286 pthread_setname_np("SCDynamicStore");
290 * process one run loop event
292 CFRunLoopRunInMode(kCFRunLoopDefaultMode
, 1.0e10
, TRUE
);
295 * check for, and if necessary, push out change notifications
296 * to other processes.