]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/PreferencePane/PrivilegedOperations.c
mDNSResponder-164.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / PreferencePane / PrivilegedOperations.c
1 /*
2 File: PrivilegedOperations.c
3
4 Abstract: Interface to "ddnswriteconfig" setuid root tool.
5
6 Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
7
8 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
9 ("Apple") in consideration of your agreement to the following terms, and your
10 use, installation, modification or redistribution of this Apple software
11 constitutes acceptance of these terms. If you do not agree with these terms,
12 please do not use, install, modify or redistribute this Apple software.
13
14 In consideration of your agreement to abide by the following terms, and subject
15 to these terms, Apple grants you a personal, non-exclusive license, under Apple's
16 copyrights in this original Apple software (the "Apple Software"), to use,
17 reproduce, modify and redistribute the Apple Software, with or without
18 modifications, in source and/or binary forms; provided that if you redistribute
19 the Apple Software in its entirety and without modifications, you must retain
20 this notice and the following text and disclaimers in all such redistributions of
21 the Apple Software. Neither the name, trademarks, service marks or logos of
22 Apple Computer, Inc. may be used to endorse or promote products derived from the
23 Apple Software without specific prior written permission from Apple. Except as
24 expressly stated in this notice, no other rights or licenses, express or implied,
25 are granted by Apple herein, including but not limited to any patent rights that
26 may be infringed by your derivative works or by other works in which the Apple
27 Software may be incorporated.
28
29 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
30 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
31 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
33 COMBINATION WITH YOUR PRODUCTS.
34
35 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
36 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
37 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
39 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
40 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
41 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
43 Change History (most recent first):
44
45 $Log: PrivilegedOperations.c,v $
46 Revision 1.7 2007/02/09 00:39:06 cheshire
47 Fix compile warnings
48
49 Revision 1.6 2006/08/14 23:15:47 cheshire
50 Tidy up Change History comment
51
52 Revision 1.5 2006/06/10 02:07:11 mkrochma
53 Whoa. Make sure code compiles before checking it in.
54
55 Revision 1.4 2006/05/27 02:32:38 mkrochma
56 Wait for installer script to exit before returning result
57
58 Revision 1.3 2005/06/04 04:50:00 cheshire
59 <rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
60 Use installtool instead of requiring ddnswriteconfig to self-install
61
62 Revision 1.2 2005/02/10 22:35:20 cheshire
63 <rdar://problem/3727944> Update name
64
65 Revision 1.1 2005/02/05 01:59:19 cheshire
66 Add Preference Pane to facilitate testing of DDNS & wide-area features
67
68 */
69
70 #include "PrivilegedOperations.h"
71 #include "ConfigurationAuthority.h"
72 #include <CoreFoundation/CoreFoundation.h>
73 #include <SystemConfiguration/SystemConfiguration.h>
74 #include <stdio.h>
75 #include <stdint.h>
76 #include <stdlib.h>
77 #include <unistd.h>
78 #include <sys/wait.h>
79 #include <AssertMacros.h>
80 #include <Security/Security.h>
81
82 Boolean gToolApproved = false;
83
84 static pid_t execTool(const char *args[])
85 // fork/exec and return new pid
86 {
87 pid_t child;
88
89 child = vfork();
90 if (child == 0)
91 {
92 execv(args[0], (char *const *)args);
93 printf("exec of %s failed; errno = %d\n", args[0], errno);
94 _exit(-1); // exec failed
95 }
96 else
97 return child;
98 }
99
100 OSStatus EnsureToolInstalled(void)
101 // Make sure that the tool is installed in the right place, with the right privs, and the right version.
102 {
103 CFURLRef bundleURL;
104 pid_t toolPID;
105 int status;
106 OSStatus err = noErr;
107 const char *args[] = { kToolPath, "0", "V", NULL };
108 char toolSourcePath[PATH_MAX] = {};
109 char toolInstallerPath[PATH_MAX] = {};
110
111 if (gToolApproved)
112 return noErr;
113
114 // Check version of installed tool
115 toolPID = execTool(args);
116 if (toolPID > 0)
117 {
118 waitpid(toolPID, &status, 0);
119 if (WIFEXITED(status) && WEXITSTATUS(status) == PRIV_OP_TOOL_VERS)
120 return noErr;
121 }
122
123 // Locate our in-bundle copy of privop tool
124 bundleURL = CFBundleCopyBundleURL(CFBundleGetBundleWithIdentifier(CFSTR("com.apple.preference.bonjour")) );
125 if (bundleURL != NULL)
126 {
127 CFURLGetFileSystemRepresentation(bundleURL, false, (UInt8*) toolSourcePath, sizeof toolSourcePath);
128 if (strlcat(toolSourcePath, "/Contents/Resources/" kToolName, sizeof toolSourcePath ) >= sizeof toolSourcePath ) return(-1);
129 CFURLGetFileSystemRepresentation(bundleURL, false, (UInt8*) toolInstallerPath, sizeof toolInstallerPath);
130 if (strlcat(toolInstallerPath, "/Contents/Resources/" kToolInstaller, sizeof toolInstallerPath) >= sizeof toolInstallerPath) return(-1);
131 }
132 else
133 return coreFoundationUnknownErr;
134
135 // Obtain authorization and run in-bundle copy as root to install it
136 {
137 AuthorizationItem aewpRight = { kAuthorizationRightExecute, strlen(toolInstallerPath), toolInstallerPath, 0 };
138 AuthorizationItemSet rights = { 1, &aewpRight };
139 AuthorizationRef authRef;
140
141 err = AuthorizationCreate(&rights, (AuthorizationEnvironment*) NULL,
142 kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights |
143 kAuthorizationFlagPreAuthorize, &authRef);
144 if (err == noErr)
145 {
146 char *installerargs[] = { toolSourcePath, NULL };
147 err = AuthorizationExecuteWithPrivileges(authRef, toolInstallerPath, 0, installerargs, (FILE**) NULL);
148 if (err == noErr) {
149 int status;
150 int pid = wait(&status);
151 if (pid > 0 && WIFEXITED(status)) {
152 err = WEXITSTATUS(status);
153 if (err == noErr) {
154 gToolApproved = true;
155 }
156 } else {
157 err = -1;
158 }
159 }
160 (void) AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
161 }
162 }
163
164 return err;
165 }
166
167
168 static OSStatus ExecWithCmdAndParam(const char *subCmd, CFDataRef paramData)
169 // Execute our privop tool with the supplied subCmd and parameter
170 {
171 OSStatus err = noErr;
172 int commFD, dataLen;
173 u_int32_t len;
174 pid_t child;
175 char fileNum[16];
176 UInt8 *buff;
177 const char *args[] = { kToolPath, NULL, "A", NULL, NULL };
178 AuthorizationExternalForm authExt;
179
180 err = ExternalizeAuthority(&authExt);
181 require_noerr(err, AuthFailed);
182
183 dataLen = CFDataGetLength(paramData);
184 buff = (UInt8*) malloc(dataLen * sizeof(UInt8));
185 require_action(buff != NULL, AllocBuffFailed, err=memFullErr;);
186 {
187 CFRange all = { 0, dataLen };
188 CFDataGetBytes(paramData, all, buff);
189 }
190
191 commFD = fileno(tmpfile());
192 sprintf(fileNum, "%d", commFD);
193 args[1] = fileNum;
194 args[3] = subCmd;
195
196 // write authority to pipe
197 len = 0; // tag, unused
198 write(commFD, &len, sizeof len);
199 len = sizeof authExt; // len
200 write(commFD, &len, sizeof len);
201 write(commFD, &authExt, len);
202
203 // write parameter to pipe
204 len = 0; // tag, unused
205 write(commFD, &len, sizeof len);
206 len = dataLen; // len
207 write(commFD, &len, sizeof len);
208 write(commFD, buff, len);
209
210 child = execTool(args);
211 if (child > 0) {
212 int status;
213 waitpid(child, &status, 0);
214 if (WIFEXITED(status))
215 err = WEXITSTATUS(status);
216 //fprintf(stderr, "child exited; status = %d (%ld)\n", status, err);
217 }
218
219 close(commFD);
220
221 free(buff);
222 AllocBuffFailed:
223 AuthFailed:
224 return err;
225 }
226
227 OSStatus
228 WriteBrowseDomain(CFDataRef domainArrayData)
229 {
230 if (!CurrentlyAuthorized())
231 return authFailErr;
232 return ExecWithCmdAndParam("Wb", domainArrayData);
233 }
234
235 OSStatus
236 WriteRegistrationDomain(CFDataRef domainArrayData)
237 {
238 if (!CurrentlyAuthorized())
239 return authFailErr;
240 return ExecWithCmdAndParam("Wd", domainArrayData);
241 }
242
243 OSStatus
244 WriteHostname(CFDataRef domainArrayData)
245 {
246 if (!CurrentlyAuthorized())
247 return authFailErr;
248 return ExecWithCmdAndParam("Wh", domainArrayData);
249 }
250
251 OSStatus
252 SetKeyForDomain(CFDataRef secretData)
253 {
254 if (!CurrentlyAuthorized())
255 return authFailErr;
256 return ExecWithCmdAndParam("Wk", secretData);
257 }