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