Imported Upstream version 765.50.9
[platform/upstream/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-2015 Apple Inc. All rights reserved.
7
8     Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 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 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
44 #include "PrivilegedOperations.h"
45 #include "ConfigurationAuthority.h"
46 #include <CoreFoundation/CoreFoundation.h>
47 #include <SystemConfiguration/SystemConfiguration.h>
48 #include <stdio.h>
49 #include <stdint.h>
50 #include <stdlib.h>
51 #include <spawn.h>
52 #include <sys/wait.h>
53 #include <AssertMacros.h>
54 #include <Security/Security.h>
55
56 extern char **environ;
57 Boolean gToolApproved = false;
58
59 static pid_t execTool(const char *args[])
60 {
61     pid_t child;
62
63     int err = posix_spawn(&child, args[0], NULL, NULL, (char *const *)args, environ);
64     if (err)
65     {
66         printf("exec of %s failed; err = %d\n", args[0], err);
67         return -1;
68     }
69     else
70         return child;
71 }
72
73 OSStatus EnsureToolInstalled(void)
74 // Make sure that the tool is installed in the right place, with the right privs, and the right version.
75 {
76     CFURLRef bundleURL;
77     pid_t toolPID;
78     int status = 0;
79     OSStatus err = noErr;
80     const char      *args[] = { kToolPath, "0", "V", NULL };
81     char toolSourcePath[PATH_MAX] = {};
82     char toolInstallerPath[PATH_MAX] = {};
83
84     if (gToolApproved)
85         return noErr;
86
87     // Check version of installed tool
88     toolPID = execTool(args);
89     if (toolPID > 0)
90     {
91         waitpid(toolPID, &status, 0);
92         if (WIFEXITED(status) && WEXITSTATUS(status) == PRIV_OP_TOOL_VERS)
93             return noErr;
94     }
95
96     // Locate our in-bundle copy of privop tool
97     bundleURL = CFBundleCopyBundleURL(CFBundleGetBundleWithIdentifier(CFSTR("com.apple.preference.bonjour")) );
98     if (bundleURL != NULL)
99     {
100         CFURLGetFileSystemRepresentation(bundleURL, false, (UInt8*) toolSourcePath, sizeof toolSourcePath);
101         CFURLGetFileSystemRepresentation(bundleURL, false, (UInt8*) toolInstallerPath, sizeof toolInstallerPath);
102         CFRelease(bundleURL);
103
104         if (strlcat(toolSourcePath,    "/Contents/Resources/" kToolName,      sizeof toolSourcePath   ) >= sizeof toolSourcePath   ) return(-1);
105         if (strlcat(toolInstallerPath, "/Contents/Resources/" kToolInstaller, sizeof toolInstallerPath) >= sizeof toolInstallerPath) return(-1);
106     }
107     else
108         return coreFoundationUnknownErr;
109
110     // Obtain authorization and run in-bundle copy as root to install it
111     {
112         AuthorizationItem aewpRight = { kAuthorizationRightExecute, strlen(toolInstallerPath), toolInstallerPath, 0 };
113         AuthorizationItemSet rights = { 1, &aewpRight };
114         AuthorizationRef authRef;
115
116         err = AuthorizationCreate(&rights, (AuthorizationEnvironment*) NULL,
117                                   kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights |
118                                   kAuthorizationFlagPreAuthorize, &authRef);
119         if (err == noErr)
120         {
121             char *installerargs[] = { toolSourcePath, NULL };
122             err = AuthorizationExecuteWithPrivileges(authRef, toolInstallerPath, 0, installerargs, (FILE**) NULL);
123             if (err == noErr)
124             {
125                 int pid = wait(&status);
126                 if (pid > 0 && WIFEXITED(status))
127                 {
128                     err = WEXITSTATUS(status);
129                     if (err == noErr)
130                     {
131                         gToolApproved = true;
132                     }
133                 } else {
134                     err = -1;
135                 }
136             }
137             (void) AuthorizationFree(authRef, kAuthorizationFlagDefaults);
138         }
139     }
140
141     return err;
142 }
143
144
145 static OSStatus ExecWithCmdAndParam(const char *subCmd, CFDataRef paramData)
146 // Execute our privop tool with the supplied subCmd and parameter
147 {
148     OSStatus err = noErr;
149     int commFD, dataLen;
150     u_int32_t len;
151     pid_t child;
152     char fileNum[16];
153     UInt8                   *buff;
154     const char              *args[] = { kToolPath, NULL, "A", NULL, NULL };
155     AuthorizationExternalForm authExt;
156
157     err = ExternalizeAuthority(&authExt);
158     require_noerr(err, AuthFailed);
159
160     dataLen = CFDataGetLength(paramData);
161     buff = (UInt8*) malloc(dataLen * sizeof(UInt8));
162     require_action(buff != NULL, AllocBuffFailed, err=memFullErr;);
163     {
164         CFRange all = { 0, dataLen };
165         CFDataGetBytes(paramData, all, buff);
166     }
167
168     commFD = fileno(tmpfile());
169     snprintf(fileNum, sizeof(fileNum), "%d", commFD);
170     args[1] = fileNum;
171     args[3] = subCmd;
172
173     // write authority to pipe
174     len = 0;    // tag, unused
175     write(commFD, &len, sizeof len);
176     len = sizeof authExt;   // len
177     write(commFD, &len, sizeof len);
178     write(commFD, &authExt, len);
179
180     // write parameter to pipe
181     len = 0;    // tag, unused
182     write(commFD, &len, sizeof len);
183     len = dataLen;  // len
184     write(commFD, &len, sizeof len);
185     write(commFD, buff, len);
186
187     child = execTool(args);
188     if (child > 0)
189     {
190         int status = 0;
191         waitpid(child, &status, 0);
192         if (WIFEXITED(status))
193             err = WEXITSTATUS(status);
194         //fprintf(stderr, "child exited; status = %d (%ld)\n", status, err);
195     }
196
197     close(commFD);
198
199     free(buff);
200 AllocBuffFailed:
201 AuthFailed:
202     return err;
203 }
204
205 OSStatus
206 WriteBrowseDomain(CFDataRef domainArrayData)
207 {
208     if (!CurrentlyAuthorized())
209         return authFailErr;
210     return ExecWithCmdAndParam("Wb", domainArrayData);
211 }
212
213 OSStatus
214 WriteRegistrationDomain(CFDataRef domainArrayData)
215 {
216     if (!CurrentlyAuthorized())
217         return authFailErr;
218     return ExecWithCmdAndParam("Wd", domainArrayData);
219 }
220
221 OSStatus
222 WriteHostname(CFDataRef domainArrayData)
223 {
224     if (!CurrentlyAuthorized())
225         return authFailErr;
226     return ExecWithCmdAndParam("Wh", domainArrayData);
227 }
228
229 OSStatus
230 SetKeyForDomain(CFDataRef secretData)
231 {
232     if (!CurrentlyAuthorized())
233         return authFailErr;
234     return ExecWithCmdAndParam("Wk", secretData);
235 }