[118] | 1 | /*
|
---|
| 2 | File: MoreSecurity.h
|
---|
| 3 |
|
---|
| 4 | Contains: Security utilities.
|
---|
| 5 |
|
---|
| 6 | Written by: Quinn
|
---|
| 7 |
|
---|
| 8 | Copyright: Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved.
|
---|
| 9 |
|
---|
| 10 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
|
---|
| 11 | ("Apple") in consideration of your agreement to the following terms, and your
|
---|
| 12 | use, installation, modification or redistribution of this Apple software
|
---|
| 13 | constitutes acceptance of these terms. If you do not agree with these terms,
|
---|
| 14 | please do not use, install, modify or redistribute this Apple software.
|
---|
| 15 |
|
---|
| 16 | In consideration of your agreement to abide by the following terms, and subject
|
---|
| 17 | to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
|
---|
| 18 | copyrights in this original Apple software (the "Apple Software"), to use,
|
---|
| 19 | reproduce, modify and redistribute the Apple Software, with or without
|
---|
| 20 | modifications, in source and/or binary forms; provided that if you redistribute
|
---|
| 21 | the Apple Software in its entirety and without modifications, you must retain
|
---|
| 22 | this notice and the following text and disclaimers in all such redistributions of
|
---|
| 23 | the Apple Software. Neither the name, trademarks, service marks or logos of
|
---|
| 24 | Apple Computer, Inc. may be used to endorse or promote products derived from the
|
---|
| 25 | Apple Software without specific prior written permission from Apple. Except as
|
---|
| 26 | expressly stated in this notice, no other rights or licenses, express or implied,
|
---|
| 27 | are granted by Apple herein, including but not limited to any patent rights that
|
---|
| 28 | may be infringed by your derivative works or by other works in which the Apple
|
---|
| 29 | Software may be incorporated.
|
---|
| 30 |
|
---|
| 31 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
---|
| 32 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
---|
| 33 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
---|
| 34 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
---|
| 35 | COMBINATION WITH YOUR PRODUCTS.
|
---|
| 36 |
|
---|
| 37 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
---|
| 38 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
---|
| 39 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
---|
| 40 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
---|
| 41 | OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
|
---|
| 42 | (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
|
---|
| 43 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
| 44 |
|
---|
| 45 | Change History (most recent first):
|
---|
| 46 |
|
---|
| 47 | $Log: MoreSecurity.h,v $
|
---|
| 48 | Revision 1.5 2003/01/20 07:58:32 eskimo1
|
---|
| 49 | Corrected some misspellings.
|
---|
| 50 |
|
---|
| 51 | Revision 1.4 2002/12/12 17:47:57 eskimo1
|
---|
| 52 | There should only be one point 5 in the "how to use" comment.
|
---|
| 53 |
|
---|
| 54 | Revision 1.3 2002/12/12 15:40:19 eskimo1
|
---|
| 55 | Eliminate MoreAuthCopyRightCFString because it makes no sense. A helper tool should always have the right name hard-wired into it, and hardwiring a C string is even easier than hardwiring a CFString.
|
---|
| 56 |
|
---|
| 57 | Revision 1.2 2002/11/25 16:42:29 eskimo1
|
---|
| 58 | Significant changes. Handle more edge cases better (for example, volumes with the "ignore permissions" flag turned on). Also brought MoreSecurity more into the CoreServices world.
|
---|
| 59 |
|
---|
| 60 | Revision 1.1 2002/11/09 00:08:40 eskimo1
|
---|
| 61 | First checked in. A module containing security helpers.
|
---|
| 62 |
|
---|
| 63 |
|
---|
| 64 | */
|
---|
| 65 |
|
---|
| 66 | #pragma once
|
---|
| 67 |
|
---|
| 68 | /////////////////////////////////////////////////////////////////
|
---|
| 69 |
|
---|
| 70 | // MoreIsBetter Setup
|
---|
| 71 |
|
---|
| 72 | #include "MoreSetup.h"
|
---|
| 73 |
|
---|
| 74 | #if !TARGET_RT_MAC_MACHO
|
---|
| 75 | #error MoreSecurity requires the use of Mach-O
|
---|
| 76 | #endif
|
---|
| 77 |
|
---|
| 78 | // System prototypes
|
---|
| 79 |
|
---|
| 80 | #include <Security/Security.h>
|
---|
| 81 | #include <CoreServices/CoreServices.h>
|
---|
| 82 |
|
---|
| 83 | /////////////////////////////////////////////////////////////////
|
---|
| 84 |
|
---|
| 85 | #ifdef __cplusplus
|
---|
| 86 | extern "C" {
|
---|
| 87 | #endif
|
---|
| 88 |
|
---|
| 89 | /////////////////////////////////////////////////////////////////
|
---|
| 90 | #pragma mark ***** UID Management
|
---|
| 91 |
|
---|
| 92 | // Basic utilities to manage your UIDs in setuid root programs.
|
---|
| 93 |
|
---|
| 94 | // RUID = real user id = ID of user who is running program
|
---|
| 95 | // EUID = effective user id = ID used to restrict privileged operations
|
---|
| 96 | // SUID = saved user id = extra ID to allow setuid programs to switch in and out of privileged mode
|
---|
| 97 |
|
---|
| 98 | extern int MoreSecPermanentlySetNonPrivilegedEUID(void);
|
---|
| 99 | // Relinquish privileges by setting RUID, EUID, and SUID
|
---|
| 100 | // to the RUID.
|
---|
| 101 |
|
---|
| 102 | extern int MoreSecTemporarilySetNonPrivilegedEUID(void);
|
---|
| 103 | // Set the EUID to the RUID, which means that subsequent
|
---|
| 104 | // code runs with a non-zero EUID. The process can
|
---|
| 105 | // still switch back to EUID when needed because the
|
---|
| 106 | // SUID is still 0.
|
---|
| 107 |
|
---|
| 108 | extern int MoreSecSetPrivilegedEUID(void);
|
---|
| 109 | // Set the EUID to 0. This is only possible if either
|
---|
| 110 | // the EUID is already 0 or the SUID is 0.
|
---|
| 111 |
|
---|
| 112 | // Typical Usage Patterns
|
---|
| 113 | // ----------------------
|
---|
| 114 | // #1 -- Do privileged operation and then drop privs
|
---|
| 115 | //
|
---|
| 116 | // DoPrivilegedStuff();
|
---|
| 117 | // MoreSecPermanentlySetNonPrivilegedEUID();
|
---|
| 118 | // DoNonPrivilegedStuff();
|
---|
| 119 | //
|
---|
| 120 | // #2 -- Switch in and out of privileged mode
|
---|
| 121 | //
|
---|
| 122 | // MoreSecTemporarilySetNonPrivilegedEUID();
|
---|
| 123 | // DoNonPrivilegedStuff();
|
---|
| 124 | // MoreSecSetPrivilegedEUID();
|
---|
| 125 | // DoPrivilegedStuff();
|
---|
| 126 | // ... repeat as necessary ...
|
---|
| 127 | // MoreSecPermanentlySetNonPrivilegedEUID();
|
---|
| 128 | // DoNonPrivilegedStuff();
|
---|
| 129 | //
|
---|
| 130 |
|
---|
| 131 | /////////////////////////////////////////////////////////////////
|
---|
| 132 | #pragma mark **** Environment Management
|
---|
| 133 |
|
---|
| 134 | // This is a utility routine to destroy any environment that you might have
|
---|
| 135 | // inherited from your parent. It's most useful in a setuid root program,
|
---|
| 136 | // which has to be careful that it doesn't rely on untrusted information
|
---|
| 137 | // that it inherited. Also useful for any privileged program which wants
|
---|
| 138 | // to execute a non-privileged program and ensure that no privileged
|
---|
| 139 | // information leaks to that program.
|
---|
| 140 |
|
---|
| 141 | // The following is a set of bit masks used for the whatToDubya parameter
|
---|
| 142 | // of the MoreSecDestroyInheritedEnvironment function.
|
---|
| 143 |
|
---|
| 144 | enum {
|
---|
| 145 | kMoreSecKeepNothingMask = 0x0000,
|
---|
| 146 |
|
---|
| 147 | kMoreSecKeepArg0Mask = 0x0001,
|
---|
| 148 | // if set, don't reset argv[0] to the real
|
---|
| 149 | // executable path
|
---|
| 150 | kMoreSecKeepEnvironmentMask = 0x0002,
|
---|
| 151 | // if set, don't clear environment
|
---|
| 152 | kMoreSecKeepStandardFilesMask = 0x0004,
|
---|
| 153 | // if set, don't close stdin, stdout, stderr
|
---|
| 154 | kMoreSecKeepOtherFilesMask = 0x0008,
|
---|
| 155 | // if set, don't close other file descriptors
|
---|
| 156 | kMoreSecKeepSignalsMask = 0x0010,
|
---|
| 157 | // if set, don't reset signals to default
|
---|
| 158 | kMoreSecKeepUmaskMask = 0x0020,
|
---|
| 159 | // if set, don't reset umask
|
---|
| 160 | kMoreSecKeepNiceMask = 0x0040,
|
---|
| 161 | // if set, don't reset process nice values
|
---|
| 162 | kMoreSecKeepResourceLimitsMask = 0x0080,
|
---|
| 163 | // if set, don't reset resource limits
|
---|
| 164 | kMoreSecKeepCurrentDirMask = 0x0100,
|
---|
| 165 | // if set, don't set CWD to "/"
|
---|
| 166 | kMoreSecKeepTimersMask = 0x0200,
|
---|
| 167 | // if set, don't reset all interval timers
|
---|
| 168 |
|
---|
| 169 | kMoreSecKeepEverythingMask = 0x03FF
|
---|
| 170 | };
|
---|
| 171 |
|
---|
| 172 | extern int MoreSecDestroyInheritedEnvironment(int whatToDubya, const char **argv);
|
---|
| 173 | // This function eliminates most of the environmental
|
---|
| 174 | // factors that you have inherited from your parent
|
---|
| 175 | // process. The function is intended for use by setuid
|
---|
| 176 | // root programs, who shouldn't trust any information
|
---|
| 177 | // supplied by a potentially malicious parent process.
|
---|
| 178 | //
|
---|
| 179 | // The whatToDubya parameter is a bit mask that
|
---|
| 180 | // specifies what environmental factors to *keep*. The
|
---|
| 181 | // most secure option is to pass kMoreSecKeepNothingMask
|
---|
| 182 | // (ie 0), which means you keep no environmental factors.
|
---|
| 183 | //
|
---|
| 184 | // The argv parameter allows the function to access argv
|
---|
| 185 | // without any special magic. You can pass NULL if you
|
---|
| 186 | // whatToDubya has kMoreSecKeepArg0Mask set, which
|
---|
| 187 | // indicates that you don't want to reset argv[0].
|
---|
| 188 | //
|
---|
| 189 | // The function returns a errno-style error. If it's
|
---|
| 190 | // non-zero you probably should err on the side of
|
---|
| 191 | // caution and refuse to start up.
|
---|
| 192 |
|
---|
| 193 | /////////////////////////////////////////////////////////////////
|
---|
| 194 | #pragma mark **** Helper Tool Big Picture
|
---|
| 195 |
|
---|
| 196 | // These utilities let you easily implement a setuid helper tool.
|
---|
| 197 | // This design is largely stolen from the DTS sample code "AuthSample",
|
---|
| 198 | // with refinements to cover more cases and allow easy code reuse.
|
---|
| 199 | //
|
---|
| 200 | // <http://developer.apple.com/samplecode/Sample_Code/Security/AuthSample.htm>
|
---|
| 201 | //
|
---|
| 202 | // To create a setuid root help tool, follow these simple instructions.
|
---|
| 203 | //
|
---|
| 204 | // 1. Define a request/response protocol based around CFDictionaries.
|
---|
| 205 | // This is as simple as defining the set of keys in the request
|
---|
| 206 | // that describe the operation you want to do, and the set of
|
---|
| 207 | // keys in the response that hold the results of those operations
|
---|
| 208 | // (if any).
|
---|
| 209 | //
|
---|
| 210 | // 2. Create a helper tool whose "main" function looks like:
|
---|
| 211 | //
|
---|
| 212 | // int main(int argc, const char *argv[])
|
---|
| 213 | // {
|
---|
| 214 | // int err;
|
---|
| 215 | // int result;
|
---|
| 216 | // AuthorizationRef auth;
|
---|
| 217 | //
|
---|
| 218 | // auth = MoreSecHelperToolCopyAuthRef();
|
---|
| 219 | //
|
---|
| 220 | // err = MoreSecDestroyInheritedEnvironment(kMoreSecKeepStandardFilesMask, argv);
|
---|
| 221 | // if (err == 0) {
|
---|
| 222 | // err = MoreUNIXIgnoreSIGPIPE();
|
---|
| 223 | // }
|
---|
| 224 | // if (err == 0) {
|
---|
| 225 | // err = MoreSecHelperToolMain(STDIN_FILENO, STDOUT_FILENO, auth, MyCommandProc, argc, argv);
|
---|
| 226 | // }
|
---|
| 227 | //
|
---|
| 228 | // return MoreSecErrorToHelperToolResult(err);
|
---|
| 229 | // }
|
---|
| 230 | //
|
---|
| 231 | // MyCommandProc is a callback that is executed when a request is
|
---|
| 232 | // passed to the tool. It can do privileged operations, such as
|
---|
| 233 | // committing changes to System Configuration framework. Its
|
---|
| 234 | // parameters are passed to it as a CFDictionary. It can pass results
|
---|
| 235 | // back to the application by creating a response dictionary.
|
---|
| 236 | //
|
---|
| 237 | // 3. Put the tool in the "MacOS" folder inside your application package.
|
---|
| 238 | // Decide on two tool names, one for the original template tool
|
---|
| 239 | // (for example, "HelperToolTemplate") and one for the working copy
|
---|
| 240 | // of the tool (for example, "HelperTool").
|
---|
| 241 | //
|
---|
| 242 | // 4. In your application, use MoreSecCopyHelperToolURLAndCheckBundled to find
|
---|
| 243 | // (or create) the working copy of your tool.
|
---|
| 244 | //
|
---|
| 245 | // err = MoreSecCopyHelperToolURLAndCheckBundled(CFBundleGetMainBundle(), CFSTR("HelperToolTemplate"),
|
---|
| 246 | // kApplicationSupportFolderType, CFSTR("My Application Name"), CFSTR("HelperTool"),
|
---|
| 247 | // &tool);
|
---|
| 248 | //
|
---|
| 249 | // The working copy of the helper tool will exist within the user's
|
---|
| 250 | // Application Support folder. See the description of
|
---|
| 251 | // MoreSecCopyHelperToolURLAndCheck[Bundled] for an explanation of this.
|
---|
| 252 | //
|
---|
| 253 | // 5. Then use MoreSecExecuteRequestInHelperTool to execute the tool, passing it
|
---|
| 254 | // a request dictionary. On success, you'll get back a response dictionary. Use
|
---|
| 255 | // MoreSecGetErrorFromResponse to extract the error result from your tool's
|
---|
| 256 | // MyCommandProc routine.
|
---|
| 257 | //
|
---|
| 258 | // 6. For extra credit, use AuthorizationCopyRights to have your tool
|
---|
| 259 | // be self-limiting, as described in the Authorization Services docs.
|
---|
| 260 | //
|
---|
| 261 | // <http://developer.apple.com/techpubs/macosx/CoreTechnologies/securityservices/authorizationservices/authservices.html>
|
---|
| 262 | //
|
---|
| 263 | // * * * *
|
---|
| 264 | //
|
---|
| 265 | // This complex design is required for a number of reasons.
|
---|
| 266 | //
|
---|
| 267 | // o The technique of using a self-limiting setuid root helper tool is
|
---|
| 268 | // recommended by Apple's security team.
|
---|
| 269 | //
|
---|
| 270 | // o You need to use a working helper tool and a backup helper tool
|
---|
| 271 | // because of the problems in the Mac OS X Finder. The problems
|
---|
| 272 | // are as follows:
|
---|
| 273 | //
|
---|
| 274 | // - In Mac OS X 10.0.x, the Finder will silently not copy the
|
---|
| 275 | // setuid root attribute of a helper program within your bundle.
|
---|
| 276 | //
|
---|
| 277 | // - In Mac OS X 10.1.x, the Finder will not copy the setuid root
|
---|
| 278 | // helper program within your bundle (and display a wacky error
|
---|
| 279 | // dialog).
|
---|
| 280 | //
|
---|
| 281 | // - In Mac OS X 10.2.x, the Finder will refuse to copy an application
|
---|
| 282 | // that contains a setuid root helper tool.
|
---|
| 283 | //
|
---|
| 284 | // o It's a general requirement that a Mac OS X application be
|
---|
| 285 | // self-contained, that is, it should be drag installable and not
|
---|
| 286 | // require the user to run an installer.
|
---|
| 287 | //
|
---|
| 288 | // o It's a general requirement that a Mac OS X application be runnable
|
---|
| 289 | // from a read-only volume (like a CD-ROM). Thus, you can't place
|
---|
| 290 | // the helper tool within the application bundle because copying it
|
---|
| 291 | // there would require the volume be writable.
|
---|
| 292 | //
|
---|
| 293 | // o Users can choose to ignore privileges on a particular volume
|
---|
| 294 | // by checking a checkbox in the Finder Get Info window. A setuid
|
---|
| 295 | // program on an volume that's ignoring privileges will not be
|
---|
| 296 | // effective (ie it won't run as EUID 0).
|
---|
| 297 | //
|
---|
| 298 | // By placing the setuid root helper tool within the Application Support
|
---|
| 299 | // folder, this code allows you to copy the application bundle from
|
---|
| 300 | // one disk to another without breaking it and without any weird error
|
---|
| 301 | // dialogs. In addition, you can copy the program to another machine
|
---|
| 302 | // entirely, and the only thing the user has to do is to reenter their
|
---|
| 303 | // admin password when they first run the application. Finally, the
|
---|
| 304 | // user's Application Support folder is typically inside their home
|
---|
| 305 | // directory, which is typically on the system volume, and thus is
|
---|
| 306 | // not ignoring privileges.
|
---|
| 307 |
|
---|
| 308 | /////////////////////////////////////////////////////////////////
|
---|
| 309 | #pragma mark **** Helper Tool Implementation
|
---|
| 310 |
|
---|
| 311 | // The following are special error codes used by the helper tool code.
|
---|
| 312 | // These error codes can be mapped to the helper tool return status
|
---|
| 313 | // (ie the result from main). For example, kMoreSecResultParamErr maps
|
---|
| 314 | // to a return status of 1, kMoreSecResultPrivilegesErr maps to 2,
|
---|
| 315 | // and so on.
|
---|
| 316 |
|
---|
| 317 | enum {
|
---|
| 318 | kMoreSecResultBase = 5360,
|
---|
| 319 |
|
---|
| 320 | kMoreSecResultParamErr = 5361,
|
---|
| 321 | kMoreSecResultPrivilegesErr = 5362,
|
---|
| 322 | kMoreSecResultCanceledErr = 5363,
|
---|
| 323 | kMoreSecResultInternalErrorErr = 5364,
|
---|
| 324 |
|
---|
| 325 | kMoreSecFirstResultErr = kMoreSecResultParamErr,
|
---|
| 326 | kMoreSecLastResultErr = kMoreSecResultInternalErrorErr
|
---|
| 327 |
|
---|
| 328 | // other errors defined below
|
---|
| 329 | };
|
---|
| 330 |
|
---|
| 331 | extern int MoreSecErrorToHelperToolResult(int errNum);
|
---|
| 332 | // A function to map an errno/OSStatus to a helper tool return
|
---|
| 333 | // status. The MoreSec error codes are mapped as described
|
---|
| 334 | // above, and there is a minimal amount of mapping of other
|
---|
| 335 | // OSStatus values to those codes.
|
---|
| 336 |
|
---|
| 337 | extern int MoreSecHelperToolResultToError(int toolResult);
|
---|
| 338 | // This function maps a helper tool status to the corresponding
|
---|
| 339 | // errno/OSStatus value.
|
---|
| 340 |
|
---|
| 341 | extern AuthorizationRef MoreSecHelperToolCopyAuthRef(void);
|
---|
| 342 | // When started by AuthorizationExecuteWithPrivileges, a helper tool
|
---|
| 343 | // gets some important parameters via its environment. However,
|
---|
| 344 | // a helper tool is *supposed* to blow away its environment
|
---|
| 345 | // (using MoreSecDestroyInheritedEnvironment) to minimise security
|
---|
| 346 | // risks. This routine allows the tool to recover the parameters
|
---|
| 347 | // supplied by AuthorizationExecuteWithPrivileges before it
|
---|
| 348 | // calls MoreSecDestroyInheritedEnvironment to destroy the environment.
|
---|
| 349 | //
|
---|
| 350 | // IMPORTANT: It's quite normal for this routine to return NULL.
|
---|
| 351 | // You should just pass the result straight to MoreSecHelperToolMain.
|
---|
| 352 |
|
---|
| 353 | typedef OSStatus (*MoreSecCommandProc)(AuthorizationRef auth,
|
---|
| 354 | CFDictionaryRef request, CFDictionaryRef *response);
|
---|
| 355 | // This is a callback type, called by MoreSecHelperToolMain to
|
---|
| 356 | // actually execute commands.
|
---|
| 357 | //
|
---|
| 358 | // auth will not be NULL
|
---|
| 359 | // request will not be NULL
|
---|
| 360 | // response will not be NULL
|
---|
| 361 | // *response will be NULL
|
---|
| 362 | //
|
---|
| 363 | // The EUID will be set to the RUID, while the SUID will be 0.
|
---|
| 364 | // If you need to do a privileged operation, you should
|
---|
| 365 | // temporarily set the EUID to 0 via MoreSecSetPrivilegedEUID,
|
---|
| 366 | // and set it back whenh you're done via MoreSecTemporarilySetNonPrivilegedEUID.
|
---|
| 367 | //
|
---|
| 368 | // If you don't need to return anything other than a function
|
---|
| 369 | // result to your client, you don't need to mess with response.
|
---|
| 370 | // MoreSecHelperToolMain will create a dictionary containing
|
---|
| 371 | // your function result and pass that back to the client.
|
---|
| 372 | // Even if you do return a dictionary in *response,
|
---|
| 373 | // MoreSecHelperToolMain will still put your function result into the
|
---|
| 374 | // kMoreSecErrorNumberKey key unless you've set up that key yourself.
|
---|
| 375 | //
|
---|
| 376 | // If you want to self-limit the capabilities of your helper tool,
|
---|
| 377 | // you might consider using AuthorizationCopyRights to make sure
|
---|
| 378 | // that the user has authorization to do specific operations.
|
---|
| 379 | //
|
---|
| 380 | // If you do create a response, it must be it must be flattenable via
|
---|
| 381 | // the CFPropertyList APIs.
|
---|
| 382 |
|
---|
| 383 | extern int MoreSecHelperToolMain(int fdIn, int fdOut, AuthorizationRef auth,
|
---|
| 384 | MoreSecCommandProc commandProc, int argc, const char *argv[]);
|
---|
| 385 | // This function is the helper tool half of MoreSecExecuteRequestInHelperTool.
|
---|
| 386 | // It's designed to be called directly from your helper tool's "main" function,
|
---|
| 387 | // and to implement the entire tool, calling commandProc to handle the specific
|
---|
| 388 | // command.
|
---|
| 389 | //
|
---|
| 390 | // IMPORTANT: Contrary to the usual rules, this routine disposes of
|
---|
| 391 | // auth before returning. This makes sense when you consider the
|
---|
| 392 | // standard "main" function, described above.
|
---|
| 393 | //
|
---|
| 394 | // fdIn must be non-negative, typically you pass in STDIN_FILENO
|
---|
| 395 | // fdOut must be non-negative, typically you pass in STDOUT_FILENO
|
---|
| 396 | // auth may be NULL, typically you just pass in the result of MoreSecHelperToolCopyAuthRef
|
---|
| 397 | // commandProc must not be NULL
|
---|
| 398 | // argc must be 1 or 2, depending on whether the tool is running in self-repair mode,
|
---|
| 399 | // typically you just pass in the argc that was supplied to main
|
---|
| 400 | // argv must not be NULL, typically you just pass in the value that was supplied to main
|
---|
| 401 |
|
---|
| 402 | /////////////////////////////////////////////////////////////////
|
---|
| 403 | #pragma mark **** Calling Helper Tool
|
---|
| 404 |
|
---|
| 405 | enum {
|
---|
| 406 | kMoreSecIgnoringPrivsInFolderErr = 5370
|
---|
| 407 | };
|
---|
| 408 |
|
---|
| 409 | extern OSStatus MoreSecIsFolderIgnoringPrivileges(const FSRef *folder, Boolean *ignoringPrivs);
|
---|
| 410 | // Determines whether the specified folder is on a volume that's
|
---|
| 411 | // ignoring privileges (as per the "Ignore ownership on this volume"
|
---|
| 412 | // checkbox in the Finder's Get Info dialog). There is a real API to
|
---|
| 413 | // do this but it's currently private. I've filed a request to get
|
---|
| 414 | // this made public [3061192]. Until that's done, I use a workaround
|
---|
| 415 | // that involves creating a temporary file within the folder and
|
---|
| 416 | // seeing if I can manipulate its permissions. For this workaround to
|
---|
| 417 | // work the folder must be read/write accessible.
|
---|
| 418 | //
|
---|
| 419 | // folder must not be NULL; folder must reference a folder
|
---|
| 420 | // ignoringPrivs must not be NULL;
|
---|
| 421 | // on success, *ignoringPrivs is true if the volume on which the folder
|
---|
| 422 | // resides is ignoring privileges; on error, *ignoringPrivs is undefined
|
---|
| 423 |
|
---|
| 424 | extern OSStatus MoreSecCopyHelperToolURLAndCheck(CFURLRef templateTool,
|
---|
| 425 | OSType folder, CFStringRef subFolderName, CFStringRef toolName,
|
---|
| 426 | CFURLRef *tool, Boolean *toolFound);
|
---|
| 427 | // This routine returns a CFURL to your helper tool. This CFURL typically
|
---|
| 428 | // points to a working copy of the tool inside the Application Support
|
---|
| 429 | // folder. This routine confirms that the tool exists and is valid in that
|
---|
| 430 | // location. If that check fails, it restores the tool from the template.
|
---|
| 431 | // Thus, the tool pointed to by the returned CFURL will be a valid copy of the
|
---|
| 432 | // template tool specified by templateTool.
|
---|
| 433 | //
|
---|
| 434 | // templateTool must not be NULL; the tool referenced by templateTool
|
---|
| 435 | // must exist; templateTool is a reference to your original helper tool;
|
---|
| 436 | // if your template tool is bundled within your application package, you might
|
---|
| 437 | // want to use the MoreSecCopyHelperToolURLAndCheckBundled wrapper routine
|
---|
| 438 | // (see below)
|
---|
| 439 | //
|
---|
| 440 | // folder is a Folder Manager folder selector; typically you pass kApplicationSupportFolderType
|
---|
| 441 | //
|
---|
| 442 | // subFolderName is the name of an optional sub-folder within the
|
---|
| 443 | // folder specified above; if this is not NULL, the returned URL
|
---|
| 444 | // points to within the named folder; if it is NULL, the URL points
|
---|
| 445 | // directly within the Folder Manager folder; if you don't want to
|
---|
| 446 | // pass NULL, you typically use the name of your application
|
---|
| 447 | //
|
---|
| 448 | // toolName is the name of the helper tool itself
|
---|
| 449 | //
|
---|
| 450 | // tool must not be NULL; *tool must be NULL; on success, *tool
|
---|
| 451 | // is a newly created CFURL that you must release; on error, *tool
|
---|
| 452 | // will be NULL
|
---|
| 453 | //
|
---|
| 454 | // On current systems, the returned URL will point to one of the
|
---|
| 455 | // following if the tool already exists.
|
---|
| 456 | //
|
---|
| 457 | // ~/Library/Application Support/<subFolderName>/<toolName>
|
---|
| 458 | // /Library/Application Support/<subFolderName>/<toolName>
|
---|
| 459 | // /Network/Library/Application Support/<subFolderName>/<toolName>
|
---|
| 460 | // /System/Library/Application Support/<subFolderName>/<toolName>
|
---|
| 461 | //
|
---|
| 462 | // If the tool doesn't already exist, a copy will be made in:
|
---|
| 463 | //
|
---|
| 464 | // ~/Library/Application Support/<subFolderName>/<toolName>
|
---|
| 465 | //
|
---|
| 466 | // and that URL will be return.d
|
---|
| 467 | //
|
---|
| 468 | // In all cases, you can treat <subFolderName> as the empty string
|
---|
| 469 | // if subFolderName is NULL.
|
---|
| 470 | //
|
---|
| 471 | // An error result of kMoreSecIgnoringPrivsInFolderErr means that
|
---|
| 472 | // the helper tool could not be created because the folder is
|
---|
| 473 | // on a volume that's ignoring privileges.
|
---|
| 474 | //
|
---|
| 475 | // IMPORTANT:
|
---|
| 476 | // When create the helper tool from the template tool, this only copies the
|
---|
| 477 | // data fork of the tool. If you the helper tool needs to access resources,
|
---|
| 478 | // you should either pass those resources in the request dictionary or
|
---|
| 479 | // pass it the URL of your bundle in the request dictionary.
|
---|
| 480 | //
|
---|
| 481 | // Note:
|
---|
| 482 | // This does not verify any tool checksum or digital signature,
|
---|
| 483 | // for the reasons outlined in the comment "Notes on Code Signing"
|
---|
| 484 | // (in "MoreSecurity.c").
|
---|
| 485 |
|
---|
| 486 | extern OSStatus MoreSecCopyHelperToolURLAndCheckBundled(CFBundleRef inBundle, CFStringRef templateToolName,
|
---|
| 487 | OSType folder, CFStringRef subFolderName, CFStringRef toolName,
|
---|
| 488 | CFURLRef *tool, Boolean *toolFound);
|
---|
| 489 | // Finds (or creates) a helper tool in a bundled application.
|
---|
| 490 | // inBundle and templateToolName describe the location of the template
|
---|
| 491 | // tool. folder, subFolderName, and toolName describe the location of the
|
---|
| 492 | // working copy of the tool.
|
---|
| 493 | //
|
---|
| 494 | // This routine is a simple composition of CFBundleCopyAuxiliaryExecutableURL and
|
---|
| 495 | // MoreSecCopyHelperToolURLAndCheck.
|
---|
| 496 | //
|
---|
| 497 | // inBundle must not be NULL; typically you just pass in CFBundleGetMainBundle()
|
---|
| 498 | //
|
---|
| 499 | // templateToolName must not be NULL; the tool must exist within the executable
|
---|
| 500 | // folder of inBundle
|
---|
| 501 | //
|
---|
| 502 | // See MoreSecCopyHelperToolURLAndCheck for a full description of the folder,
|
---|
| 503 | // subFolderName, and toolName parameters. Typically you pass
|
---|
| 504 | // kApplicationSupportFolderType for folder and your application name for
|
---|
| 505 | // subFolderName.
|
---|
| 506 | //
|
---|
| 507 | // tool must not be NULL; *tool must be NULL; on success, *tool will be
|
---|
| 508 | // a URL to the helper tool; on error, *tool will be NULL
|
---|
| 509 |
|
---|
| 510 | extern OSStatus MoreSecExecuteRequestInHelperTool(CFURLRef helperTool, AuthorizationRef auth,
|
---|
| 511 | CFDictionaryRef request, CFDictionaryRef *response);
|
---|
| 512 | // Executes a privileged request in a helper tool. helperTool is
|
---|
| 513 | // a reference to the helper tool to run. You typically gets its value
|
---|
| 514 | // using MoreSecCopyHelperToolURLAndCheckBundled, although it's passed in as a
|
---|
| 515 | // parameter to allow flexibility.
|
---|
| 516 | //
|
---|
| 517 | // auth is your application's connection to Authorization Services.
|
---|
| 518 | // It's likely that you've used this connection to pre-authorization
|
---|
| 519 | // this operation, as described in the Authorization Services docs.
|
---|
| 520 | //
|
---|
| 521 | // <http://developer.apple.com/techpubs/macosx/CoreTechnologies/securityservices/authorizationservices/authservices.html>
|
---|
| 522 | //
|
---|
| 523 | // request specifies what you want the helper tool to do. Its
|
---|
| 524 | // contents are not interpreted by MoreSecExecuteRequestInHelperTool,
|
---|
| 525 | // however, it must be flattenable via the CFPropertyList APIs.
|
---|
| 526 | //
|
---|
| 527 | // response is the reply from the helper tool. It is not interpreted
|
---|
| 528 | // by MoreSecExecuteRequestInHelperTool other than to add a key
|
---|
| 529 | // (kMoreSecErrorNumberKey) which contains the error from the
|
---|
| 530 | // helper tool's commandProc.
|
---|
| 531 | //
|
---|
| 532 | // helperTool must not be NULL
|
---|
| 533 | // auth must not be NULL
|
---|
| 534 | // request must not be NULL
|
---|
| 535 | // response must not be NULL
|
---|
| 536 | // *response must be NULL
|
---|
| 537 |
|
---|
| 538 | extern OSStatus MoreSecGetErrorFromResponse(CFDictionaryRef response);
|
---|
| 539 | // this function returns the error stored in a helper tool
|
---|
| 540 | // response obtained via MoreSecExecuteRequestInHelperTool.
|
---|
| 541 | //
|
---|
| 542 | // response must not be NULL
|
---|
| 543 |
|
---|
| 544 | #define kMoreSecErrorNumberKey CFSTR("com.apple.dts.MoreIsBetter.MoreSec.ErrorNumber") // CFNumberRef, OSStatus
|
---|
| 545 | // The dictionary key where the helper tool error is stored.
|
---|
| 546 |
|
---|
| 547 | #ifdef __cplusplus
|
---|
| 548 | }
|
---|
| 549 | #endif
|
---|