]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/helper/SCHelper_client.c
3fe56db0b2835a43a8c09a203dfaed30ae6a254c
[apple/configd.git] / SystemConfiguration.fproj / helper / SCHelper_client.c
1 /*
2 * Copyright (c) 2005-2007 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/wait.h>
35
36 #include <CoreFoundation/CoreFoundation.h>
37 #include <SystemConfiguration/SCPrivate.h>
38
39 #include "SCHelper_client.h"
40 #include "helper_comm.h"
41
42
43 #define HELPER "SCHelper"
44 #define HELPER_LEN (sizeof(HELPER) - 1)
45
46 #define SUFFIX_SYM "~sym"
47 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
48
49
50 __private_extern__
51 int
52 _SCHelperOpen(CFDataRef authorizationData)
53 {
54 sigset_t block;
55 sigset_t block_old;
56 CFBundleRef bundle;
57 int comm[2] = { -1, -1 };
58 int exit_status = 0;
59 struct sigaction ignore;
60 struct sigaction int_old;
61 Boolean ok = FALSE;
62 char path[MAXPATHLEN]= { 0 };
63 pid_t pid1;
64 struct sigaction quit_old;
65 uint32_t status = 0;
66 CFURLRef url = NULL;
67 static int yes = 1;
68
69 // get CFBundleRef for SystemConfiguration.framework
70 bundle = _SC_CFBundleGet();
71 if (bundle != NULL) {
72 url = CFBundleCopyResourceURL(bundle, CFSTR(HELPER), NULL, NULL);
73 }
74
75 if (url != NULL) {
76 if (!CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)path, sizeof(path))) {
77 path[0] = 0;
78 }
79 CFRelease(url);
80 }
81
82 // create tool<-->helper communications socket
83 if (socketpair(AF_UNIX, SOCK_STREAM, 0, comm) == -1) {
84 perror("_SCHelperOpen socketpair() failed");
85 return -1;
86 }
87
88 // ignore SIGINT, SIGQUIT
89 ignore.sa_handler = SIG_IGN;
90 ignore.sa_flags = 0;
91 (void)sigemptyset(&ignore.sa_mask);
92 (void)sigaction(SIGINT , &ignore, &int_old );
93 (void)sigaction(SIGQUIT, &ignore, &quit_old);
94
95 // block SIGCHLD
96 (void)sigemptyset(&block);
97 (void)sigaddset(&block, SIGCHLD);
98 (void)sigprocmask(SIG_BLOCK, &block, &block_old);
99
100 // fork
101 pid1 = fork();
102 if (pid1 == -1) { // if error
103 perror("_SCHelperOpen fork() failed");
104 goto done;
105 } else if (pid1 == 0) { // if [first] child
106 int i;
107 pid_t pid2;
108
109 // make sure that we don't step on syslog's FD (if open)
110 closelog();
111
112 // set stdin, stdout, stderr (and close other FD's)
113 if (comm[0] != STDIN_FILENO) {
114 (void)dup2(comm[0], STDIN_FILENO);
115 }
116
117 if (comm[0] != STDOUT_FILENO) {
118 (void)dup2(comm[0], STDOUT_FILENO);
119 }
120
121 (void)close(STDERR_FILENO);
122 (void)open(_PATH_CONSOLE, O_WRONLY, 0);
123
124 for (i = getdtablesize() - 1; i > STDERR_FILENO; i--) {
125 (void)close(i);
126 }
127
128 pid2 = vfork();
129 if (pid2 == -1) { // if error
130 int err = errno;
131
132 perror("_SCHelperOpen vfork() failed\n");
133 (void)__SCHelper_txMessage(STDOUT_FILENO, err, NULL);
134 _exit(err);
135 } else if (pid2 == 0) { // if [second] child
136 char *env;
137 int err = ENOENT;
138 size_t len;
139
140 // restore signal processing
141 (void)sigaction(SIGINT , &int_old , NULL);
142 (void)sigaction(SIGQUIT, &quit_old, NULL);
143 (void)sigprocmask(SIG_SETMASK, &block_old, NULL);
144
145 if (path[0] != 0) {
146 (void)execl(path, path, NULL);
147 err = errno;
148 }
149
150 // if appropriate (e.g. when debugging), try a bit harder
151
152 env = getenv("DYLD_FRAMEWORK_PATH");
153 len = (env != NULL) ? strlen(env) : 0;
154
155 // trim any trailing slashes
156 while ((len > 1) && (env[len - 1] == '/')) {
157 len--;
158 }
159
160 // if DYLD_FRAMEWORK_PATH is ".../xxx~sym" than try ".../xxx~sym/SCHelper"
161 if ((len > SUFFIX_SYM_LEN) &&
162 (strncmp(&env[len - SUFFIX_SYM_LEN], SUFFIX_SYM, SUFFIX_SYM_LEN) == 0) &&
163 ((len + 1 + HELPER_LEN) < MAXPATHLEN)) {
164 char path[MAXPATHLEN];
165
166 strlcpy(path, env, sizeof(path));
167 strlcpy(&path[len], "/", sizeof(path) - (len - 1));
168 strlcat(&path[len], HELPER, sizeof(path) - len);
169
170 (void)execl(path, path, NULL);
171 err = errno;
172 }
173
174 // if SCHelper could not be started
175 (void)__SCHelper_txMessage(STDOUT_FILENO, err, NULL);
176 _exit(err != 0 ? err : ENOENT);
177 }
178
179 // [first] child
180 _exit(0);
181 }
182
183 if (wait4(pid1, &exit_status, 0, NULL) == -1) {
184 perror("_SCHelperOpen wait4() failed");
185 goto done;
186 }
187
188 if (WIFEXITED(exit_status)) {
189 if (WEXITSTATUS(exit_status) != 0) {
190 SCLog(TRUE, LOG_INFO,
191 CFSTR("could not start \"" HELPER "[1]\", exited w/status = %d"),
192 WEXITSTATUS(exit_status));
193 goto done;
194 }
195 } else if (WIFSIGNALED(exit_status)) {
196 SCLog(TRUE, LOG_INFO,
197 CFSTR("could not start \"" HELPER "[1]\", terminated w/signal = %d"),
198 WTERMSIG(exit_status));
199 goto done;
200 } else {
201 SCLog(TRUE, LOG_INFO,
202 CFSTR("could not start \"" HELPER "[1]\", exit_status = %x"),
203 exit_status);
204 goto done;
205 }
206
207 (void)close(comm[0]);
208 comm[0] = -1;
209
210 if (setsockopt(comm[1], SOL_SOCKET, SO_NOSIGPIPE, (const void *)&yes, sizeof(yes)) == -1) {
211 perror("_SCHelperOpen setsockopt() failed");
212 goto done;
213 }
214
215 ok = __SCHelper_rxMessage(comm[1], &status, NULL);
216 if (!ok) {
217 SCLog(TRUE, LOG_INFO, CFSTR("could not start \"" HELPER "\", no status available"));
218 goto done;
219 }
220
221 ok = (status == 0);
222 if (!ok) {
223 SCLog(TRUE, LOG_INFO, CFSTR("could not start \"" HELPER "\", status = %u"), status);
224 goto done;
225 }
226
227 ok = _SCHelperExec(comm[1], SCHELPER_MSG_AUTH, authorizationData, &status, NULL);
228 if (!ok) {
229 SCLog(TRUE, LOG_INFO, CFSTR("_SCHelperOpen: could not send authorization"));
230 goto done;
231 }
232
233 done :
234
235 // restore signal processing
236 (void)sigaction(SIGINT , &int_old , NULL);
237 (void)sigaction(SIGQUIT, &quit_old, NULL);
238 (void)sigprocmask(SIG_SETMASK, &block_old, NULL);
239
240 if (comm[0] > 0) {
241 (void)close(comm[0]);
242 // comm[0] = -1;
243 }
244
245 if (!ok) {
246 (void)close(comm[1]);
247 comm[1] = -1;
248 }
249
250 return comm[1];
251 }
252
253
254 __private_extern__
255 void
256 _SCHelperClose(int helper)
257 {
258 if (!_SCHelperExec(helper, SCHELPER_MSG_EXIT, NULL, NULL, NULL)) {
259 SCLog(TRUE, LOG_INFO, CFSTR("_SCHelperOpen: could not send exit request"));
260 }
261
262 (void)close(helper);
263 return;
264 }