1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/mac/authorization_util.h"
7 #import <Foundation/Foundation.h>
12 #include "base/basictypes.h"
13 #include "base/logging.h"
14 #include "base/mac/bundle_locations.h"
15 #include "base/mac/mac_logging.h"
16 #import "base/mac/mac_util.h"
17 #include "base/mac/scoped_authorizationref.h"
18 #include "base/posix/eintr_wrapper.h"
19 #include "base/string_util.h"
20 #include "base/strings/string_number_conversions.h"
25 AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt) {
26 // Create an empty AuthorizationRef.
27 ScopedAuthorizationRef authorization;
28 OSStatus status = AuthorizationCreate(NULL,
29 kAuthorizationEmptyEnvironment,
30 kAuthorizationFlagDefaults,
32 if (status != errAuthorizationSuccess) {
33 OSSTATUS_LOG(ERROR, status) << "AuthorizationCreate";
37 // Specify the "system.privilege.admin" right, which allows
38 // AuthorizationExecuteWithPrivileges to run commands as root.
39 AuthorizationItem right_items[] = {
40 {kAuthorizationRightExecute, 0, NULL, 0}
42 AuthorizationRights rights = {arraysize(right_items), right_items};
44 // product_logo_32.png is used instead of app.icns because Authorization
45 // Services can't deal with .icns files.
47 [base::mac::FrameworkBundle() pathForResource:@"product_logo_32"
49 const char* icon_path_c = [icon_path fileSystemRepresentation];
50 size_t icon_path_length = icon_path_c ? strlen(icon_path_c) : 0;
52 // The OS will append " Type an administrator's name and password to allow
53 // <CFBundleDisplayName> to make changes."
54 NSString* prompt_ns = base::mac::CFToNSCast(prompt);
55 const char* prompt_c = [prompt_ns UTF8String];
56 size_t prompt_length = prompt_c ? strlen(prompt_c) : 0;
58 AuthorizationItem environment_items[] = {
59 {kAuthorizationEnvironmentIcon, icon_path_length, (void*)icon_path_c, 0},
60 {kAuthorizationEnvironmentPrompt, prompt_length, (void*)prompt_c, 0}
63 AuthorizationEnvironment environment = {arraysize(environment_items),
66 AuthorizationFlags flags = kAuthorizationFlagDefaults |
67 kAuthorizationFlagInteractionAllowed |
68 kAuthorizationFlagExtendRights |
69 kAuthorizationFlagPreAuthorize;
71 status = AuthorizationCopyRights(authorization,
76 if (status != errAuthorizationSuccess) {
77 if (status != errAuthorizationCanceled) {
78 OSSTATUS_LOG(ERROR, status) << "AuthorizationCopyRights";
83 return authorization.release();
86 OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
87 const char* tool_path,
88 AuthorizationFlags options,
89 const char** arguments,
92 // pipe may be NULL, but this function needs one. In that case, use a local
99 pipe_pointer = &local_pipe;
102 // AuthorizationExecuteWithPrivileges wants |char* const*| for |arguments|,
103 // but it doesn't actually modify the arguments, and that type is kind of
104 // silly and callers probably aren't dealing with that. Put the cast here
105 // to make things a little easier on callers.
106 OSStatus status = AuthorizationExecuteWithPrivileges(authorization,
109 (char* const*)arguments,
111 if (status != errAuthorizationSuccess) {
116 size_t line_length = 0;
117 char* line_c = fgetln(*pipe_pointer, &line_length);
119 if (line_length > 0 && line_c[line_length - 1] == '\n') {
120 // line_c + line_length is the start of the next line if there is one.
121 // Back up one character.
124 std::string line(line_c, line_length);
125 if (!base::StringToInt(line, &line_pid)) {
126 // StringToInt may have set line_pid to something, but if the conversion
127 // was imperfect, use -1.
128 LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: funny line: " << line;
132 LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: no line";
136 fclose(*pipe_pointer);
146 OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization,
147 const char* tool_path,
148 AuthorizationFlags options,
149 const char** arguments,
153 OSStatus status = ExecuteWithPrivilegesAndGetPID(authorization,
159 if (status != errAuthorizationSuccess) {
163 // exit_status may be NULL, but this function needs it. In that case, use a
165 int local_exit_status;
166 int* exit_status_pointer;
168 exit_status_pointer = exit_status;
170 exit_status_pointer = &local_exit_status;
174 pid_t wait_result = HANDLE_EINTR(waitpid(pid, exit_status_pointer, 0));
175 if (wait_result != pid) {
176 PLOG(ERROR) << "waitpid";
177 *exit_status_pointer = -1;
180 *exit_status_pointer = -1;