Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MoreAuthSample/MoreSecurity/MoreSecurity.h
/* |
File: MoreSecurity.h |
Contains: Security utilities. |
Written by: Quinn |
Copyright: Copyright (c) 2002 by Apple Computer, Inc., All Rights Reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Change History (most recent first): |
$Log: MoreSecurity.h,v $ |
Revision 1.6 2003/05/25 12:30:58 eskimo1 |
Added support for descriptor passing. |
Revision 1.5 2003/01/20 07:58:32 eskimo1 |
Corrected some misspellings. |
Revision 1.4 2002/12/12 17:47:57 eskimo1 |
There should only be one point 5 in the "how to use" comment. |
Revision 1.3 2002/12/12 15:40:19 eskimo1 |
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. |
Revision 1.2 2002/11/25 16:42:29 eskimo1 |
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. |
Revision 1.1 2002/11/09 00:08:40 eskimo1 |
First checked in. A module containing security helpers. |
*/ |
#pragma once |
///////////////////////////////////////////////////////////////// |
// MoreIsBetter Setup |
#include "MoreSetup.h" |
#if !TARGET_RT_MAC_MACHO |
#error MoreSecurity requires the use of Mach-O |
#endif |
// System prototypes |
#include <Security/Security.h> |
#include <CoreServices/CoreServices.h> |
///////////////////////////////////////////////////////////////// |
#ifdef __cplusplus |
extern "C" { |
#endif |
///////////////////////////////////////////////////////////////// |
#pragma mark ***** UID Management |
// Basic utilities to manage your UIDs in setuid root programs. |
// RUID = real user id = ID of user who is running program |
// EUID = effective user id = ID used to restrict privileged operations |
// SUID = saved user id = extra ID to allow setuid programs to switch in and out of privileged mode |
extern int MoreSecPermanentlySetNonPrivilegedEUID(void); |
// Relinquish privileges by setting RUID, EUID, and SUID |
// to the RUID. |
extern int MoreSecTemporarilySetNonPrivilegedEUID(void); |
// Set the EUID to the RUID, which means that subsequent |
// code runs with a non-zero EUID. The process can |
// still switch back to EUID when needed because the |
// SUID is still 0. |
extern int MoreSecSetPrivilegedEUID(void); |
// Set the EUID to 0. This is only possible if either |
// the EUID is already 0 or the SUID is 0. |
// Typical Usage Patterns |
// ---------------------- |
// #1 -- Do privileged operation and then drop privs |
// |
// DoPrivilegedStuff(); |
// MoreSecPermanentlySetNonPrivilegedEUID(); |
// DoNonPrivilegedStuff(); |
// |
// #2 -- Switch in and out of privileged mode |
// |
// MoreSecTemporarilySetNonPrivilegedEUID(); |
// DoNonPrivilegedStuff(); |
// MoreSecSetPrivilegedEUID(); |
// DoPrivilegedStuff(); |
// ... repeat as necessary ... |
// MoreSecPermanentlySetNonPrivilegedEUID(); |
// DoNonPrivilegedStuff(); |
// |
///////////////////////////////////////////////////////////////// |
#pragma mark **** Environment Management |
// This is a utility routine to destroy any environment that you might have |
// inherited from your parent. It's most useful in a setuid root program, |
// which has to be careful that it doesn't rely on untrusted information |
// that it inherited. Also useful for any privileged program which wants |
// to execute a non-privileged program and ensure that no privileged |
// information leaks to that program. |
// The following is a set of bit masks used for the whatToDubya parameter |
// of the MoreSecDestroyInheritedEnvironment function. |
enum { |
kMoreSecKeepNothingMask = 0x0000, |
kMoreSecKeepArg0Mask = 0x0001, |
// if set, don't reset argv[0] to the real |
// executable path |
kMoreSecKeepEnvironmentMask = 0x0002, |
// if set, don't clear environment |
kMoreSecKeepStandardFilesMask = 0x0004, |
// if set, don't close stdin, stdout, stderr |
kMoreSecKeepOtherFilesMask = 0x0008, |
// if set, don't close other file descriptors |
kMoreSecKeepSignalsMask = 0x0010, |
// if set, don't reset signals to default |
kMoreSecKeepUmaskMask = 0x0020, |
// if set, don't reset umask |
kMoreSecKeepNiceMask = 0x0040, |
// if set, don't reset process nice values |
kMoreSecKeepResourceLimitsMask = 0x0080, |
// if set, don't reset resource limits |
kMoreSecKeepCurrentDirMask = 0x0100, |
// if set, don't set CWD to "/" |
kMoreSecKeepTimersMask = 0x0200, |
// if set, don't reset all interval timers |
kMoreSecKeepEverythingMask = 0x03FF |
}; |
extern int MoreSecDestroyInheritedEnvironment(int whatToDubya, const char **argv); |
// This function eliminates most of the environmental |
// factors that you have inherited from your parent |
// process. The function is intended for use by setuid |
// root programs, who shouldn't trust any information |
// supplied by a potentially malicious parent process. |
// |
// The whatToDubya parameter is a bit mask that |
// specifies what environmental factors to *keep*. The |
// most secure option is to pass kMoreSecKeepNothingMask |
// (ie 0), which means you keep no environmental factors. |
// |
// The argv parameter allows the function to access argv |
// without any special magic. You can pass NULL if you |
// whatToDubya has kMoreSecKeepArg0Mask set, which |
// indicates that you don't want to reset argv[0]. |
// |
// The function returns a errno-style error. If it's |
// non-zero you probably should err on the side of |
// caution and refuse to start up. |
///////////////////////////////////////////////////////////////// |
#pragma mark **** Helper Tool Big Picture |
// These utilities let you easily implement a setuid helper tool. |
// This design is largely stolen from the DTS sample code "AuthSample", |
// with refinements to cover more cases and allow easy code reuse. |
// |
// <http://developer.apple.com/samplecode/Sample_Code/Security/AuthSample.htm> |
// |
// To create a setuid root help tool, follow these simple instructions. |
// |
// 1. Define a request/response protocol based around CFDictionaries. |
// This is as simple as defining the set of keys in the request |
// that describe the operation you want to do, and the set of |
// keys in the response that hold the results of those operations |
// (if any). |
// |
// 2. Create a helper tool whose "main" function looks like: |
// |
// int main(int argc, const char *argv[]) |
// { |
// int err; |
// int result; |
// AuthorizationRef auth; |
// |
// auth = MoreSecHelperToolCopyAuthRef(); |
// |
// err = MoreSecDestroyInheritedEnvironment(kMoreSecKeepStandardFilesMask, argv); |
// if (err == 0) { |
// err = MoreUNIXIgnoreSIGPIPE(); |
// } |
// if (err == 0) { |
// err = MoreSecHelperToolMain(STDIN_FILENO, STDOUT_FILENO, auth, MyCommandProc, argc, argv); |
// } |
// |
// return MoreSecErrorToHelperToolResult(err); |
// } |
// |
// MyCommandProc is a callback that is executed when a request is |
// passed to the tool. It can do privileged operations, such as |
// committing changes to System Configuration framework. Its |
// parameters are passed to it as a CFDictionary. It can pass results |
// back to the application by creating a response dictionary. |
// |
// 3. Put the tool in the "MacOS" folder inside your application package. |
// Decide on two tool names, one for the original template tool |
// (for example, "HelperToolTemplate") and one for the working copy |
// of the tool (for example, "HelperTool"). |
// |
// 4. In your application, use MoreSecCopyHelperToolURLAndCheckBundled to find |
// (or create) the working copy of your tool. |
// |
// err = MoreSecCopyHelperToolURLAndCheckBundled(CFBundleGetMainBundle(), CFSTR("HelperToolTemplate"), |
// kApplicationSupportFolderType, CFSTR("My Application Name"), CFSTR("HelperTool"), |
// &tool); |
// |
// The working copy of the helper tool will exist within the user's |
// Application Support folder. See the description of |
// MoreSecCopyHelperToolURLAndCheck[Bundled] for an explanation of this. |
// |
// 5. Then use MoreSecExecuteRequestInHelperTool to execute the tool, passing it |
// a request dictionary. On success, you'll get back a response dictionary. Use |
// MoreSecGetErrorFromResponse to extract the error result from your tool's |
// MyCommandProc routine. |
// |
// 6. For extra credit, use AuthorizationCopyRights to have your tool |
// be self-limiting, as described in the Authorization Services docs. |
// |
// <http://developer.apple.com/techpubs/macosx/CoreTechnologies/securityservices/authorizationservices/authservices.html> |
// |
// * * * * |
// |
// This complex design is required for a number of reasons. |
// |
// o The technique of using a self-limiting setuid root helper tool is |
// recommended by Apple's security team. |
// |
// o You need to use a working helper tool and a backup helper tool |
// because of the problems in the Mac OS X Finder. The problems |
// are as follows: |
// |
// - In Mac OS X 10.0.x, the Finder will silently not copy the |
// setuid root attribute of a helper program within your bundle. |
// |
// - In Mac OS X 10.1.x, the Finder will not copy the setuid root |
// helper program within your bundle (and display a wacky error |
// dialog). |
// |
// - In Mac OS X 10.2.x, the Finder will refuse to copy an application |
// that contains a setuid root helper tool. |
// |
// o It's a general requirement that a Mac OS X application be |
// self-contained, that is, it should be drag installable and not |
// require the user to run an installer. |
// |
// o It's a general requirement that a Mac OS X application be runnable |
// from a read-only volume (like a CD-ROM). Thus, you can't place |
// the helper tool within the application bundle because copying it |
// there would require the volume be writable. |
// |
// o Users can choose to ignore privileges on a particular volume |
// by checking a checkbox in the Finder Get Info window. A setuid |
// program on an volume that's ignoring privileges will not be |
// effective (ie it won't run as EUID 0). |
// |
// By placing the setuid root helper tool within the Application Support |
// folder, this code allows you to copy the application bundle from |
// one disk to another without breaking it and without any weird error |
// dialogs. In addition, you can copy the program to another machine |
// entirely, and the only thing the user has to do is to reenter their |
// admin password when they first run the application. Finally, the |
// user's Application Support folder is typically inside their home |
// directory, which is typically on the system volume, and thus is |
// not ignoring privileges. |
///////////////////////////////////////////////////////////////// |
#pragma mark **** Helper Tool Implementation |
// The following are special error codes used by the helper tool code. |
// These error codes can be mapped to the helper tool return status |
// (ie the result from main). For example, kMoreSecResultParamErr maps |
// to a return status of 1, kMoreSecResultPrivilegesErr maps to 2, |
// and so on. |
enum { |
kMoreSecResultBase = 5360, |
kMoreSecResultParamErr = 5361, |
kMoreSecResultPrivilegesErr = 5362, |
kMoreSecResultCanceledErr = 5363, |
kMoreSecResultInternalErrorErr = 5364, |
kMoreSecFirstResultErr = kMoreSecResultParamErr, |
kMoreSecLastResultErr = kMoreSecResultInternalErrorErr |
// other errors defined below |
}; |
extern int MoreSecErrorToHelperToolResult(int errNum); |
// A function to map an errno/OSStatus to a helper tool return |
// status. The MoreSec error codes are mapped as described |
// above, and there is a minimal amount of mapping of other |
// OSStatus values to those codes. |
extern int MoreSecHelperToolResultToError(int toolResult); |
// This function maps a helper tool status to the corresponding |
// errno/OSStatus value. |
extern AuthorizationRef MoreSecHelperToolCopyAuthRef(void); |
// When started by AuthorizationExecuteWithPrivileges, a helper tool |
// gets some important parameters via its environment. However, |
// a helper tool is *supposed* to blow away its environment |
// (using MoreSecDestroyInheritedEnvironment) to minimise security |
// risks. This routine allows the tool to recover the parameters |
// supplied by AuthorizationExecuteWithPrivileges before it |
// calls MoreSecDestroyInheritedEnvironment to destroy the environment. |
// |
// IMPORTANT: It's quite normal for this routine to return NULL. |
// You should just pass the result straight to MoreSecHelperToolMain. |
typedef OSStatus (*MoreSecCommandProc)(AuthorizationRef auth, |
CFDictionaryRef request, CFDictionaryRef *response); |
// This is a callback type, called by MoreSecHelperToolMain to |
// actually execute commands. |
// |
// auth will not be NULL |
// request will not be NULL |
// response will not be NULL |
// *response will be NULL |
// |
// The EUID will be set to the RUID, while the SUID will be 0. |
// If you need to do a privileged operation, you should |
// temporarily set the EUID to 0 via MoreSecSetPrivilegedEUID, |
// and set it back whenh you're done via MoreSecTemporarilySetNonPrivilegedEUID. |
// |
// If you don't need to return anything other than a function |
// result to your client, you don't need to mess with response. |
// MoreSecHelperToolMain will create a dictionary containing |
// your function result and pass that back to the client. |
// Even if you do return a dictionary in *response, |
// MoreSecHelperToolMain will still put your function result into the |
// kMoreSecErrorNumberKey key unless you've set up that key yourself. |
// |
// If you want to self-limit the capabilities of your helper tool, |
// you might consider using AuthorizationCopyRights to make sure |
// that the user has authorization to do specific operations. |
// |
// If you do create a response, it must be it must be flattenable via |
// the CFPropertyList APIs. |
// |
// If the response contains a key kMoreSecFileDescriptorsKey, that key |
// must be an array of valid file descriptors. [See the declaration of |
// kMoreSecFileDescriptorsKey for more information on the format.] Those file |
// descriptors are passed back to the calling process via descriptor passing on |
// a UNIX domain socket. This allows your helper tool to open privileged |
// descriptors (for example, TCP sockets bound to a low-numbered port) and pass |
// them back to the calling application. |
// |
// These descriptors are closed by the MoreSecurity infrastructure or |
// by the calling process. This is an unusual design style for me |
// (I ususually prefer that the entity that creates a resource be |
// responsible for destroying it), but it's unavoidable in this case. |
// The descriptor are opened by customised code (that is, this callback |
// but no other customised code is executed before the tool returns |
// from main, so there's no opportunity for customised code to close the |
// descriptors. Hence MoreSecurity must do it for you. |
extern int MoreSecHelperToolMain(int fdIn, int fdOut, AuthorizationRef auth, |
MoreSecCommandProc commandProc, int argc, const char *argv[]); |
// This function is the helper tool half of MoreSecExecuteRequestInHelperTool. |
// It's designed to be called directly from your helper tool's "main" function, |
// and to implement the entire tool, calling commandProc to handle the specific |
// command. |
// |
// IMPORTANT: Contrary to the usual rules, this routine disposes of |
// auth before returning. This makes sense when you consider the |
// standard "main" function, described above. |
// |
// fdIn must be non-negative, typically you pass in STDIN_FILENO |
// fdOut must be non-negative, typically you pass in STDOUT_FILENO |
// auth may be NULL, typically you just pass in the result of MoreSecHelperToolCopyAuthRef |
// commandProc must not be NULL |
// argc must be 1 or 2, depending on whether the tool is running in self-repair mode, |
// typically you just pass in the argc that was supplied to main |
// argv must not be NULL, typically you just pass in the value that was supplied to main |
///////////////////////////////////////////////////////////////// |
#pragma mark **** Calling Helper Tool |
enum { |
kMoreSecIgnoringPrivsInFolderErr = 5370 |
}; |
extern OSStatus MoreSecIsFolderIgnoringPrivileges(const FSRef *folder, Boolean *ignoringPrivs); |
// Determines whether the specified folder is on a volume that's |
// ignoring privileges (as per the "Ignore ownership on this volume" |
// checkbox in the Finder's Get Info dialog). There is a real API to |
// do this but it's currently private. I've filed a request to get |
// this made public [3061192]. Until that's done, I use a workaround |
// that involves creating a temporary file within the folder and |
// seeing if I can manipulate its permissions. For this workaround to |
// work the folder must be read/write accessible. |
// |
// folder must not be NULL; folder must reference a folder |
// ignoringPrivs must not be NULL; |
// on success, *ignoringPrivs is true if the volume on which the folder |
// resides is ignoring privileges; on error, *ignoringPrivs is undefined |
extern OSStatus MoreSecCopyHelperToolURLAndCheck(CFURLRef templateTool, |
OSType folder, CFStringRef subFolderName, CFStringRef toolName, |
CFURLRef *tool); |
// This routine returns a CFURL to your helper tool. This CFURL typically |
// points to a working copy of the tool inside the Application Support |
// folder. This routine confirms that the tool exists and is valid in that |
// location. If that check fails, it restores the tool from the template. |
// Thus, the tool pointed to by the returned CFURL will be a valid copy of the |
// template tool specified by templateTool. |
// |
// templateTool must not be NULL; the tool referenced by templateTool |
// must exist; templateTool is a reference to your original helper tool; |
// if your template tool is bundled within your application package, you might |
// want to use the MoreSecCopyHelperToolURLAndCheckBundled wrapper routine |
// (see below) |
// |
// folder is a Folder Manager folder selector; typically you pass kApplicationSupportFolderType |
// |
// subFolderName is the name of an optional sub-folder within the |
// folder specified above; if this is not NULL, the returned URL |
// points to within the named folder; if it is NULL, the URL points |
// directly within the Folder Manager folder; if you don't want to |
// pass NULL, you typically use the name of your application |
// |
// toolName is the name of the helper tool itself |
// |
// tool must not be NULL; *tool must be NULL; on success, *tool |
// is a newly created CFURL that you must release; on error, *tool |
// will be NULL |
// |
// On current systems, the returned URL will point to one of the |
// following if the tool already exists. |
// |
// ~/Library/Application Support/<subFolderName>/<toolName> |
// /Library/Application Support/<subFolderName>/<toolName> |
// /Network/Library/Application Support/<subFolderName>/<toolName> |
// /System/Library/Application Support/<subFolderName>/<toolName> |
// |
// If the tool doesn't already exist, a copy will be made in: |
// |
// ~/Library/Application Support/<subFolderName>/<toolName> |
// |
// and that URL will be return.d |
// |
// In all cases, you can treat <subFolderName> as the empty string |
// if subFolderName is NULL. |
// |
// An error result of kMoreSecIgnoringPrivsInFolderErr means that |
// the helper tool could not be created because the folder is |
// on a volume that's ignoring privileges. |
// |
// IMPORTANT: |
// When create the helper tool from the template tool, this only copies the |
// data fork of the tool. If you the helper tool needs to access resources, |
// you should either pass those resources in the request dictionary or |
// pass it the URL of your bundle in the request dictionary. |
// |
// Note: |
// This does not verify any tool checksum or digital signature, |
// for the reasons outlined in the comment "Notes on Code Signing" |
// (in "MoreSecurity.c"). |
extern OSStatus MoreSecCopyHelperToolURLAndCheckBundled(CFBundleRef inBundle, CFStringRef templateToolName, |
OSType folder, CFStringRef subFolderName, CFStringRef toolName, |
CFURLRef *tool); |
// Finds (or creates) a helper tool in a bundled application. |
// inBundle and templateToolName describe the location of the template |
// tool. folder, subFolderName, and toolName describe the location of the |
// working copy of the tool. |
// |
// This routine is a simple composition of CFBundleCopyAuxiliaryExecutableURL and |
// MoreSecCopyHelperToolURLAndCheck. |
// |
// inBundle must not be NULL; typically you just pass in CFBundleGetMainBundle() |
// |
// templateToolName must not be NULL; the tool must exist within the executable |
// folder of inBundle |
// |
// See MoreSecCopyHelperToolURLAndCheck for a full description of the folder, |
// subFolderName, and toolName parameters. Typically you pass |
// kApplicationSupportFolderType for folder and your application name for |
// subFolderName. |
// |
// tool must not be NULL; *tool must be NULL; on success, *tool will be |
// a URL to the helper tool; on error, *tool will be NULL |
extern OSStatus MoreSecExecuteRequestInHelperTool(CFURLRef helperTool, AuthorizationRef auth, |
CFDictionaryRef request, CFDictionaryRef *response); |
// Executes a privileged request in a helper tool. helperTool is |
// a reference to the helper tool to run. You typically gets its value |
// using MoreSecCopyHelperToolURLAndCheckBundled, although it's passed in as a |
// parameter to allow flexibility. |
// |
// auth is your application's connection to Authorization Services. |
// It's likely that you've used this connection to pre-authorization |
// this operation, as described in the Authorization Services docs. |
// |
// <http://developer.apple.com/techpubs/macosx/CoreTechnologies/securityservices/authorizationservices/authservices.html> |
// |
// request specifies what you want the helper tool to do. Its |
// contents are not interpreted by MoreSecExecuteRequestInHelperTool, |
// however, it must be flattenable via the CFPropertyList APIs. |
// |
// response is the reply from the helper tool. It is not interpreted |
// by MoreSecExecuteRequestInHelperTool other than to: |
// |
// o add a key (kMoreSecErrorNumberKey) which contains the error from the |
// helper tool's commandProc, and |
// |
// o transfer any file descriptors returned from the tool (in the |
// kMoreSecFileDescriptorsKey, see below for more details) to the |
// calling process. |
// |
// IMPORTANT: |
// You are responsible for closing any file descriptors returned by the |
// helper tool. The MoreSecCloseDescriptorArray helper routine may be |
// useful for this. |
// |
// helperTool must not be NULL |
// auth must not be NULL |
// request must not be NULL |
// response must not be NULL |
// *response must be NULL |
extern OSStatus MoreSecGetErrorFromResponse(CFDictionaryRef response); |
// this function returns the error stored in a helper tool |
// response obtained via MoreSecExecuteRequestInHelperTool. |
// |
// response must not be NULL |
#define kMoreSecErrorNumberKey CFSTR("com.apple.dts.MoreIsBetter.MoreSec.ErrorNumber") // CFNumberRef, OSStatus |
// The dictionary key where the helper tool error is stored. |
#define kMoreSecFileDescriptorsKey CFSTR("com.apple.dts.MoreIsBetter.MoreSec.FDs") // CFArray of CFNumber of kCFNumberIntType |
// If the helper tool returns file descriptors to your application, |
// they will be stored in this key within the response. The key value |
// will be a CFArray. Each element of the CFArray will be a CFNumber |
// of format kCFNumberIntType. Each number will be a valid file |
// descriptor returned from the helper tool. |
// |
// See the discussion of MoreSecCommandProc for more information about this. |
extern void MoreSecCloseDescriptorArray(CFArrayRef descArray); |
// Given an array of descriptors (as described in the discussion of |
// kMoreSecFileDescriptorsKey), this routine closes all of the |
// descriptors. |
// |
// On input, descArray may be NULL; if so, this routine does nothing; |
// if not, descArray must be a CFArray of CFNumbers, where each |
// number is a descriptor to be closed |
#ifdef __cplusplus |
} |
#endif |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-06-12