2 * Copyright (c) 2005-2007 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@
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
36 #include <CoreFoundation/CoreFoundation.h>
37 #include <SystemConfiguration/SCPrivate.h>
39 #include "SCHelper_client.h"
40 #include "helper_comm.h"
43 #define HELPER "SCHelper"
44 #define HELPER_LEN (sizeof(HELPER) - 1)
46 #define SUFFIX_SYM "~sym"
47 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
52 _SCHelperOpen(CFDataRef authorizationData
)
57 int comm
[2] = { -1, -1 };
59 struct sigaction ignore
;
60 struct sigaction int_old
;
62 char path
[MAXPATHLEN
]= { 0 };
64 struct sigaction quit_old
;
69 // get CFBundleRef for SystemConfiguration.framework
70 bundle
= _SC_CFBundleGet();
72 url
= CFBundleCopyResourceURL(bundle
, CFSTR(HELPER
), NULL
, NULL
);
76 if (!CFURLGetFileSystemRepresentation(url
, TRUE
, (UInt8
*)path
, sizeof(path
))) {
82 // create tool<-->helper communications socket
83 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, comm
) == -1) {
84 perror("_SCHelperOpen socketpair() failed");
88 // ignore SIGINT, SIGQUIT
89 ignore
.sa_handler
= SIG_IGN
;
91 (void)sigemptyset(&ignore
.sa_mask
);
92 (void)sigaction(SIGINT
, &ignore
, &int_old
);
93 (void)sigaction(SIGQUIT
, &ignore
, &quit_old
);
96 (void)sigemptyset(&block
);
97 (void)sigaddset(&block
, SIGCHLD
);
98 (void)sigprocmask(SIG_BLOCK
, &block
, &block_old
);
102 if (pid1
== -1) { // if error
103 perror("_SCHelperOpen fork() failed");
105 } else if (pid1
== 0) { // if [first] child
109 // make sure that we don't step on syslog's FD (if open)
112 // set stdin, stdout, stderr (and close other FD's)
113 if (comm
[0] != STDIN_FILENO
) {
114 (void)dup2(comm
[0], STDIN_FILENO
);
117 if (comm
[0] != STDOUT_FILENO
) {
118 (void)dup2(comm
[0], STDOUT_FILENO
);
121 (void)close(STDERR_FILENO
);
122 (void)open(_PATH_CONSOLE
, O_WRONLY
, 0);
124 for (i
= getdtablesize() - 1; i
> STDERR_FILENO
; i
--) {
129 if (pid2
== -1) { // if error
132 perror("_SCHelperOpen vfork() failed\n");
133 (void)__SCHelper_txMessage(STDOUT_FILENO
, err
, NULL
);
135 } else if (pid2
== 0) { // if [second] child
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
);
146 (void)execl(path
, path
, NULL
);
150 // if appropriate (e.g. when debugging), try a bit harder
152 env
= getenv("DYLD_FRAMEWORK_PATH");
153 len
= (env
!= NULL
) ? strlen(env
) : 0;
155 // trim any trailing slashes
156 while ((len
> 1) && (env
[len
- 1] == '/')) {
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
];
166 strlcpy(path
, env
, sizeof(path
));
167 strlcpy(&path
[len
], "/", sizeof(path
) - (len
- 1));
168 strlcat(&path
[len
], HELPER
, sizeof(path
) - len
);
170 (void)execl(path
, path
, NULL
);
174 // if SCHelper could not be started
175 (void)__SCHelper_txMessage(STDOUT_FILENO
, err
, NULL
);
176 _exit(err
!= 0 ? err
: ENOENT
);
183 if (wait4(pid1
, &exit_status
, 0, NULL
) == -1) {
184 perror("_SCHelperOpen wait4() failed");
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
));
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
));
201 SCLog(TRUE
, LOG_INFO
,
202 CFSTR("could not start \"" HELPER
"[1]\", exit_status = %x"),
207 (void)close(comm
[0]);
210 if (setsockopt(comm
[1], SOL_SOCKET
, SO_NOSIGPIPE
, (const void *)&yes
, sizeof(yes
)) == -1) {
211 perror("_SCHelperOpen setsockopt() failed");
215 ok
= __SCHelper_rxMessage(comm
[1], &status
, NULL
);
217 SCLog(TRUE
, LOG_INFO
, CFSTR("could not start \"" HELPER
"\", no status available"));
223 SCLog(TRUE
, LOG_INFO
, CFSTR("could not start \"" HELPER
"\", status = %u"), status
);
227 ok
= _SCHelperExec(comm
[1], SCHELPER_MSG_AUTH
, authorizationData
, &status
, NULL
);
229 SCLog(TRUE
, LOG_INFO
, CFSTR("_SCHelperOpen: could not send authorization"));
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
);
241 (void)close(comm
[0]);
246 (void)close(comm
[1]);
256 _SCHelperClose(int helper
)
258 if (!_SCHelperExec(helper
, SCHELPER_MSG_EXIT
, NULL
, NULL
, NULL
)) {
259 SCLog(TRUE
, LOG_INFO
, CFSTR("_SCHelperOpen: could not send exit request"));