OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/browser/mac/authorization_util.h" | |
6 | |
7 #import <Foundation/Foundation.h> | |
8 #include <sys/wait.h> | |
9 | |
10 #include <string> | |
11 | |
12 #include "base/basictypes.h" | |
13 #include "base/eintr_wrapper.h" | |
14 #include "base/logging.h" | |
15 #include "base/mac/bundle_locations.h" | |
16 #include "base/mac/mac_logging.h" | |
17 #import "base/mac/mac_util.h" | |
18 #include "base/string_number_conversions.h" | |
19 #include "base/string_util.h" | |
20 #include "chrome/browser/mac/scoped_authorizationref.h" | |
21 | |
22 namespace authorization_util { | |
23 | |
24 AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt) { | |
25 // Create an empty AuthorizationRef. | |
26 ScopedAuthorizationRef authorization; | |
27 OSStatus status = AuthorizationCreate(NULL, | |
28 kAuthorizationEmptyEnvironment, | |
29 kAuthorizationFlagDefaults, | |
30 &authorization); | |
31 if (status != errAuthorizationSuccess) { | |
32 OSSTATUS_LOG(ERROR, status) << "AuthorizationCreate"; | |
33 return NULL; | |
34 } | |
35 | |
36 // Specify the "system.privilege.admin" right, which allows | |
37 // AuthorizationExecuteWithPrivileges to run commands as root. | |
38 AuthorizationItem right_items[] = { | |
39 {kAuthorizationRightExecute, 0, NULL, 0} | |
40 }; | |
41 AuthorizationRights rights = {arraysize(right_items), right_items}; | |
42 | |
43 // product_logo_32.png is used instead of app.icns because Authorization | |
44 // Services can't deal with .icns files. | |
45 NSString* icon_path = | |
46 [base::mac::FrameworkBundle() pathForResource:@"product_logo_32" | |
47 ofType:@"png"]; | |
48 const char* icon_path_c = [icon_path fileSystemRepresentation]; | |
49 size_t icon_path_length = icon_path_c ? strlen(icon_path_c) : 0; | |
50 | |
51 // The OS will append " Type an administrator's name and password to allow | |
52 // <CFBundleDisplayName> to make changes." | |
53 NSString* prompt_ns = base::mac::CFToNSCast(prompt); | |
54 const char* prompt_c = [prompt_ns UTF8String]; | |
55 size_t prompt_length = prompt_c ? strlen(prompt_c) : 0; | |
56 | |
57 AuthorizationItem environment_items[] = { | |
58 {kAuthorizationEnvironmentIcon, icon_path_length, (void*)icon_path_c, 0}, | |
59 {kAuthorizationEnvironmentPrompt, prompt_length, (void*)prompt_c, 0} | |
60 }; | |
61 | |
62 AuthorizationEnvironment environment = {arraysize(environment_items), | |
63 environment_items}; | |
64 | |
65 AuthorizationFlags flags = kAuthorizationFlagDefaults | | |
66 kAuthorizationFlagInteractionAllowed | | |
67 kAuthorizationFlagExtendRights | | |
68 kAuthorizationFlagPreAuthorize; | |
69 | |
70 status = AuthorizationCopyRights(authorization, | |
71 &rights, | |
72 &environment, | |
73 flags, | |
74 NULL); | |
75 if (status != errAuthorizationSuccess) { | |
76 if (status != errAuthorizationCanceled) { | |
77 OSSTATUS_LOG(ERROR, status) << "AuthorizationCopyRights"; | |
78 } | |
79 return NULL; | |
80 } | |
81 | |
82 return authorization.release(); | |
83 } | |
84 | |
85 OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization, | |
86 const char* tool_path, | |
87 AuthorizationFlags options, | |
88 const char** arguments, | |
89 FILE** pipe, | |
90 pid_t* pid) { | |
91 // pipe may be NULL, but this function needs one. In that case, use a local | |
92 // pipe. | |
93 FILE* local_pipe; | |
94 FILE** pipe_pointer; | |
95 if (pipe) { | |
96 pipe_pointer = pipe; | |
97 } else { | |
98 pipe_pointer = &local_pipe; | |
99 } | |
100 | |
101 // AuthorizationExecuteWithPrivileges wants |char* const*| for |arguments|, | |
102 // but it doesn't actually modify the arguments, and that type is kind of | |
103 // silly and callers probably aren't dealing with that. Put the cast here | |
104 // to make things a little easier on callers. | |
105 OSStatus status = AuthorizationExecuteWithPrivileges(authorization, | |
106 tool_path, | |
107 options, | |
108 (char* const*)arguments, | |
109 pipe_pointer); | |
110 if (status != errAuthorizationSuccess) { | |
111 return status; | |
112 } | |
113 | |
114 int line_pid = -1; | |
115 size_t line_length = 0; | |
116 char* line_c = fgetln(*pipe_pointer, &line_length); | |
117 if (line_c) { | |
118 if (line_length > 0 && line_c[line_length - 1] == '\n') { | |
119 // line_c + line_length is the start of the next line if there is one. | |
120 // Back up one character. | |
121 --line_length; | |
122 } | |
123 std::string line(line_c, line_length); | |
124 if (!base::StringToInt(line, &line_pid)) { | |
125 // StringToInt may have set line_pid to something, but if the conversion | |
126 // was imperfect, use -1. | |
127 LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: funny line: " << line; | |
128 line_pid = -1; | |
129 } | |
130 } else { | |
131 LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: no line"; | |
132 } | |
133 | |
134 if (!pipe) { | |
135 fclose(*pipe_pointer); | |
136 } | |
137 | |
138 if (pid) { | |
139 *pid = line_pid; | |
140 } | |
141 | |
142 return status; | |
143 } | |
144 | |
145 OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization, | |
146 const char* tool_path, | |
147 AuthorizationFlags options, | |
148 const char** arguments, | |
149 FILE** pipe, | |
150 int* exit_status) { | |
151 pid_t pid; | |
152 OSStatus status = ExecuteWithPrivilegesAndGetPID(authorization, | |
153 tool_path, | |
154 options, | |
155 arguments, | |
156 pipe, | |
157 &pid); | |
158 if (status != errAuthorizationSuccess) { | |
159 return status; | |
160 } | |
161 | |
162 // exit_status may be NULL, but this function needs it. In that case, use a | |
163 // local version. | |
164 int local_exit_status; | |
165 int* exit_status_pointer; | |
166 if (exit_status) { | |
167 exit_status_pointer = exit_status; | |
168 } else { | |
169 exit_status_pointer = &local_exit_status; | |
170 } | |
171 | |
172 if (pid != -1) { | |
173 pid_t wait_result = HANDLE_EINTR(waitpid(pid, exit_status_pointer, 0)); | |
174 if (wait_result != pid) { | |
175 PLOG(ERROR) << "waitpid"; | |
176 *exit_status_pointer = -1; | |
177 } | |
178 } else { | |
179 *exit_status_pointer = -1; | |
180 } | |
181 | |
182 return status; | |
183 } | |
184 | |
185 } // namespace authorization_util | |
OLD | NEW |