source: trunk/Cocoa/Pester/Source/MoreSecurity/MoreSecurity.h@ 118

Last change on this file since 118 was 118, checked in by Nicholas Riley, 21 years ago

Broken, to-be-removed authorization implementation

File size: 24.1 KB
Line 
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 $
48Revision 1.5 2003/01/20 07:58:32 eskimo1
49Corrected some misspellings.
50
51Revision 1.4 2002/12/12 17:47:57 eskimo1
52There should only be one point 5 in the "how to use" comment.
53
54Revision 1.3 2002/12/12 15:40:19 eskimo1
55Eliminate 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
57Revision 1.2 2002/11/25 16:42:29 eskimo1
58Significant 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
60Revision 1.1 2002/11/09 00:08:40 eskimo1
61First 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
86extern "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
98extern int MoreSecPermanentlySetNonPrivilegedEUID(void);
99 // Relinquish privileges by setting RUID, EUID, and SUID
100 // to the RUID.
101
102extern 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
108extern 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
144enum {
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
172extern 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
317enum {
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
331extern 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
337extern int MoreSecHelperToolResultToError(int toolResult);
338 // This function maps a helper tool status to the corresponding
339 // errno/OSStatus value.
340
341extern 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
353typedef 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
383extern 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
405enum {
406 kMoreSecIgnoringPrivsInFolderErr = 5370
407};
408
409extern 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
424extern 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
486extern 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
510extern 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
538extern 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
Note: See TracBrowser for help on using the repository browser.