]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/helper/SCHelper_client.c
configd-395.6.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / helper / SCHelper_client.c
1 /*
2 * Copyright (c) 2005-2007, 2010 Apple 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 #include <fcntl.h>
25 #include <paths.h>
26 #include <signal.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/un.h>
35 #include <sys/wait.h>
36 #include <mach/mach.h>
37 #include <mach/mach_error.h>
38 #include <servers/bootstrap.h>
39 #include <bootstrap_priv.h>
40
41 #include <CoreFoundation/CoreFoundation.h>
42 #include <SystemConfiguration/SCPrivate.h>
43
44 #include "SCHelper_client.h"
45 #include "helper.h" // MiG generated file
46
47
48 #define HELPER "SCHelper"
49 #define HELPER_LEN (sizeof(HELPER) - 1)
50
51 #define SUFFIX_SYM "~sym"
52 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
53
54
55 static pthread_mutex_t _helper_lock = PTHREAD_MUTEX_INITIALIZER;
56 static mach_port_t _helper_server = MACH_PORT_NULL;
57
58
59 static mach_port_t
60 __SCHelperServerPort(kern_return_t *status)
61 {
62 mach_port_t server = MACH_PORT_NULL;
63 char *server_name;
64
65 server_name = getenv("SCHELPER_SERVER");
66 if (!server_name) {
67 server_name = SCHELPER_SERVER;
68 }
69
70 #ifdef BOOTSTRAP_PRIVILEGED_SERVER
71 *status = bootstrap_look_up2(bootstrap_port,
72 server_name,
73 &server,
74 0,
75 BOOTSTRAP_PRIVILEGED_SERVER);
76 #else // BOOTSTRAP_PRIVILEGED_SERVER
77 *status = bootstrap_look_up(bootstrap_port, server_name, &server);
78 #endif // BOOTSTRAP_PRIVILEGED_SERVER
79
80 switch (*status) {
81 case BOOTSTRAP_SUCCESS :
82 /* service currently registered, "a good thing" (tm) */
83 return server;
84 case BOOTSTRAP_NOT_PRIVILEGED :
85 /* the service is not privileged */
86 break;
87 case BOOTSTRAP_UNKNOWN_SERVICE :
88 /* service not currently registered, try again later */
89 break;
90 default :
91 #ifdef DEBUG
92 SCLog(_sc_verbose, LOG_DEBUG,
93 CFSTR("__SCHelperServerPort bootstrap_look_up() failed: status=%s"),
94 bootstrap_strerror(*status));
95 #endif /* DEBUG */
96 break;
97 }
98
99 return MACH_PORT_NULL;
100 }
101
102
103 __private_extern__
104 Boolean
105 _SCHelperOpen(CFDataRef authorizationData, mach_port_t *helper_port)
106 {
107 kern_return_t kr;
108 Boolean ok;
109 mach_port_t server;
110 uint32_t status = 0;
111
112 *helper_port = MACH_PORT_NULL;
113
114 // open a new session with the server
115 server = _helper_server;
116 while (TRUE) {
117 if (server != MACH_PORT_NULL) {
118 kr = helperinit(server,
119 helper_port,
120 &status);
121 if (kr == KERN_SUCCESS) {
122 break;
123 }
124
125 // our [cached] server port is not valid
126 if (kr != MACH_SEND_INVALID_DEST) {
127 // if we got an unexpected error, don't retry
128 status = kr;
129 break;
130 }
131 }
132
133 pthread_mutex_lock(&_helper_lock);
134 if (_helper_server != MACH_PORT_NULL) {
135 if (server == _helper_server) {
136 // if the server we tried returned the error
137 (void)mach_port_deallocate(mach_task_self(), _helper_server);
138 _helper_server = __SCHelperServerPort(&kr);
139 if (_helper_server == MACH_PORT_NULL) {
140 status = kr;
141 }
142 } else {
143 // another thread has refreshed the SCHelper server port
144 }
145 } else {
146 _helper_server = __SCHelperServerPort(&kr);
147 if (_helper_server == MACH_PORT_NULL) {
148 status = kr;
149 }
150 }
151 server = _helper_server;
152 pthread_mutex_unlock(&_helper_lock);
153
154 if (server == MACH_PORT_NULL) {
155 // if SCHelper server not available
156 break;
157 }
158 }
159 __MACH_PORT_DEBUG(TRUE, "*** _SCHelperOpen", *helper_port);
160
161 if (*helper_port == MACH_PORT_NULL) {
162 SCLog(TRUE, LOG_ERR,
163 CFSTR("_SCHelperOpen: could not contact server: %s"),
164 SCErrorString(status));
165 return FALSE;
166 }
167
168 ok = _SCHelperExec(*helper_port, SCHELPER_MSG_AUTH, authorizationData, &status, NULL);
169 if (!ok) {
170 SCLog(TRUE, LOG_INFO, CFSTR("_SCHelperOpen: could not send authorization"));
171 goto error;
172 }
173
174 ok = (status == 0);
175 if (!ok) {
176 SCLog(TRUE, LOG_INFO, CFSTR("could not start \"" HELPER "\", status = %u"), status);
177 goto error;
178 }
179
180 return TRUE;
181
182 error :
183
184 if (*helper_port != MACH_PORT_NULL) {
185 (void)mach_port_deallocate(mach_task_self(), *helper_port);
186 *helper_port = MACH_PORT_NULL;
187 }
188
189 return FALSE;
190
191 }
192
193
194 __private_extern__
195 void
196 _SCHelperClose(mach_port_t *helper_port)
197 {
198 if (!_SCHelperExec(*helper_port, SCHELPER_MSG_EXIT, NULL, NULL, NULL)) {
199 SCLog(TRUE, LOG_INFO, CFSTR("_SCHelperOpen: could not send exit request"));
200 }
201
202 if (*helper_port != MACH_PORT_NULL) {
203 (void)mach_port_deallocate(mach_task_self(), *helper_port);
204 *helper_port = MACH_PORT_NULL;
205 }
206
207 return;
208 }
209
210
211 Boolean
212 _SCHelperExec(mach_port_t port, uint32_t msgID, CFDataRef data, uint32_t *status, CFDataRef *reply)
213 {
214 kern_return_t kr;
215 CFDataRef myData = NULL;
216 xmlDataOut_t replyRef = NULL; /* raw bytes */
217 mach_msg_type_number_t replyLen = 0;
218 uint32_t replyStatus = 0;
219
220 kr = helperexec(port,
221 msgID,
222 (data != NULL) ? (void *)CFDataGetBytePtr(data) : NULL,
223 (data != NULL) ? CFDataGetLength(data) : 0,
224 &replyStatus,
225 &replyRef,
226 &replyLen);
227 if (kr != KERN_SUCCESS) {
228 if (replyRef != NULL) {
229 (void) vm_deallocate(mach_task_self(), (vm_address_t)replyRef, replyLen);
230 }
231
232 if (kr != MACH_SEND_INVALID_DEST) {
233 // if we got an unexpected error
234 SCLog(TRUE, LOG_ERR, CFSTR("_SCHelperExec() failed: %s"), mach_error_string(kr));
235 }
236 _SCErrorSet(kr);
237
238 return FALSE;
239 }
240
241 // un-serialize the reply
242 if (replyRef != NULL) {
243 if (!_SCUnserializeData(&myData, replyRef, replyLen)) {
244 return FALSE;
245 }
246 }
247
248 if (status != NULL) {
249 *status = replyStatus;
250 }
251
252 if (reply != NULL) {
253 *reply = myData;
254 } else if (myData != NULL) {
255 SCLog(TRUE, LOG_DEBUG, CFSTR("_SCHelperExec() data available with no place to go"));
256 CFRelease(myData);
257 }
258
259 return TRUE;
260 }