2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
22 // This file is the unified implementation of the Authorization and AuthSession APIs.
24 #include <Security/Authorization.h>
25 #include <Security/AuthorizationDB.h>
26 #include <Security/AuthorizationPriv.h>
27 #include <Security/AuthSession.h>
28 #include "AuthorizationWalkers.h"
29 #include <Security/mach++.h>
30 #include <Security/globalizer.h>
31 #include <Security/cssmalloc.h>
32 #include <Security/ssclient.h>
33 #include <Security/ktracecodes.h>
35 using namespace SecurityServer
;
36 using namespace MachPlusPlus
;
40 // Shared cached client object
42 class AuthClient
: public SecurityServer::ClientSession
{
45 : SecurityServer::ClientSession(CssmAllocator::standard(), CssmAllocator::standard())
49 static ModuleNexus
<AuthClient
> server
;
53 // Create an Authorization
55 OSStatus
AuthorizationCreate(const AuthorizationRights
*rights
,
56 const AuthorizationEnvironment
*environment
,
57 AuthorizationFlags flags
,
58 AuthorizationRef
*authorization
)
60 Debug::trace(kSecTraceAuthorizationCreateStart
);
62 AuthorizationBlob result
;
63 server().authCreate(rights
, environment
, flags
, result
);
67 (AuthorizationRef
) new(server().returnAllocator
) AuthorizationBlob(result
);
71 // If no authorizationRef is desired free the one we just created.
72 server().authRelease(result
, flags
);
74 Debug::trace(kSecTraceAuthorizationCreateEnd
);
80 // Free an authorization reference
82 OSStatus
AuthorizationFree(AuthorizationRef authorization
, AuthorizationFlags flags
)
85 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authorization
;
86 server().authRelease(Required(auth
, errAuthorizationInvalidRef
), flags
);
87 server().returnAllocator
.free(auth
);
93 // Augment and/or interrogate an authorization
95 OSStatus
AuthorizationCopyRights(AuthorizationRef authorization
,
96 const AuthorizationRights
*rights
,
97 const AuthorizationEnvironment
*environment
,
98 AuthorizationFlags flags
,
99 AuthorizationRights
**authorizedRights
)
101 Debug::trace(kSecTraceAuthorizationCopyRightsStart
);
103 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authorization
;
104 server().authCopyRights(Required(auth
, errAuthorizationInvalidRef
),
105 rights
, environment
, flags
, authorizedRights
);
106 Debug::trace(kSecTraceAuthorizationCopyRightsEnd
);
112 // Retrieve side-band information from an authorization
114 OSStatus
AuthorizationCopyInfo(AuthorizationRef authorization
,
115 AuthorizationString tag
,
116 AuthorizationItemSet
**info
)
118 Debug::trace(kSecTraceAuthorizationCopyInfoStart
);
120 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authorization
;
121 server().authCopyInfo(Required(auth
, errAuthorizationInvalidRef
),
122 tag
, Required(info
));
123 Debug::trace(kSecTraceAuthorizationCopyInfoEnd
);
129 // Externalize and internalize authorizations
131 OSStatus
AuthorizationMakeExternalForm(AuthorizationRef authorization
,
132 AuthorizationExternalForm
*extForm
)
135 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authorization
;
136 server().authExternalize(Required(auth
, errAuthorizationInvalidRef
), *extForm
);
140 OSStatus
AuthorizationCreateFromExternalForm(const AuthorizationExternalForm
*extForm
,
141 AuthorizationRef
*authorization
)
144 AuthorizationBlob result
;
145 server().authInternalize(*extForm
, result
);
146 Required(authorization
, errAuthorizationInvalidRef
) =
147 (AuthorizationRef
) new(server().returnAllocator
) AuthorizationBlob(result
);
154 // Free an ItemSet structure returned from an API call. This is a local operation.
155 // Since we allocate returned ItemSets as compact blobs, this is just a simple
158 OSStatus
AuthorizationFreeItemSet(AuthorizationItemSet
*set
)
161 server().returnAllocator
.free(set
);
162 return errAuthorizationSuccess
;
168 // Get session information
170 OSStatus
SessionGetInfo(SecuritySessionId session
,
171 SecuritySessionId
*sessionId
,
172 SessionAttributeBits
*attributes
)
175 SecuritySessionId sid
= session
;
176 server().getSessionInfo(sid
, *attributes
);
184 // Create a new session
186 OSStatus
SessionCreate(SessionCreationFlags flags
,
187 SessionAttributeBits attributes
)
191 // unless the (expert) caller has already done so, create a sub-bootstrap and set it
192 // note that this is inherently thread-unfriendly; we can't do anything about that
193 // (caller's responsibility)
195 if (!(flags
& sessionKeepCurrentBootstrap
)) {
197 bootstrap
= bootstrap
.subset(TaskPort());
198 self
.bootstrap(bootstrap
);
201 // now call the SecurityServer and tell it to initialize the (new) session
202 server().setupSession(flags
, attributes
);
204 // retrieve the (new) session id and set it into the process environment
205 SecuritySessionId id
= callerSecuritySession
;
206 SessionAttributeBits attrs
;
207 server().getSessionInfo(id
, attrs
);
209 snprintf(idString
, sizeof(idString
), "%lx", id
);
210 setenv("SECURITYSESSIONID", idString
, 1);
217 // Modify Authorization rules
221 // AuthorizationRightGet
223 OSStatus
AuthorizationRightGet(const char *rightName
, CFDictionaryRef
*rightDefinition
)
227 CssmDataContainer
definition(server().returnAllocator
);
229 server().authorizationdbGet(rightName
, definition
, server().returnAllocator
);
230 // convert rightDefinition to dictionary
234 CFRef
<CFDataRef
> data(CFDataCreate(NULL
, static_cast<UInt8
*>(definition
.data()), definition
.length()));
236 CssmError::throwMe(errAuthorizationInternal
);
238 CFRef
<CFDictionaryRef
> rightDict(static_cast<CFDictionaryRef
>(CFPropertyListCreateFromXMLData(NULL
, data
, kCFPropertyListImmutable
, NULL
)));
240 || CFGetTypeID(rightDict
) != CFDictionaryGetTypeID())
241 CssmError::throwMe(errAuthorizationInternal
);
244 *rightDefinition
= rightDict
;
251 // AuthorizationRightSet
253 OSStatus
AuthorizationRightSet(AuthorizationRef authRef
,
254 const char *rightName
, CFTypeRef rightDefinition
,
255 CFStringRef descriptionKey
, CFBundleRef bundle
, CFStringRef tableName
)
259 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authRef
;
261 CFRef
<CFMutableDictionaryRef
> rightDefinitionDict
;
262 if (rightDefinition
&& (CFGetTypeID(rightDefinition
) == CFStringGetTypeID()))
264 rightDefinitionDict
= CFDictionaryCreateMutable(NULL
, 10, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
265 if (!rightDefinitionDict
)
266 CssmError::throwMe(errAuthorizationInternal
);
267 CFDictionarySetValue(rightDefinitionDict
, CFSTR(kAuthorizationRightRule
), rightDefinition
);
270 if (rightDefinition
&& (CFGetTypeID(rightDefinition
) == CFDictionaryGetTypeID()))
272 rightDefinitionDict
= CFDictionaryCreateMutableCopy(NULL
, 0, static_cast<CFDictionaryRef
>(rightDefinition
));
273 if (!rightDefinitionDict
)
274 CssmError::throwMe(errAuthorizationInternal
);
277 CssmError::throwMe(errAuthorizationDenied
);
279 if (rightDefinitionDict
)
280 CFRelease(rightDefinitionDict
); // we just assigned things that were already retained
284 CFRef
<CFMutableDictionaryRef
> localizedDescriptions(CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
));
286 if (!localizedDescriptions
)
287 CssmError::throwMe(errAuthorizationInternal
);
289 // assigning to perform a retain on either
290 CFRef
<CFBundleRef
> clientBundle
= bundle
? bundle
: CFBundleGetMainBundle();
292 // looks like a list of CFStrings: English us_en etc.
293 CFRef
<CFArrayRef
> localizations(CFBundleCopyBundleLocalizations(clientBundle
));
297 // for every CFString in localizations do
298 CFIndex locIndex
, allLocs
= CFArrayGetCount(localizations
);
299 for (locIndex
= 0; locIndex
< allLocs
; locIndex
++)
301 CFStringRef oneLocalization
= static_cast<CFStringRef
>(CFArrayGetValueAtIndex(localizations
, locIndex
));
303 if (!oneLocalization
)
306 // @@@ no way to get "Localized" and "strings" as constants?
307 CFRef
<CFURLRef
> locURL(CFBundleCopyResourceURLForLocalization(clientBundle
, tableName
? tableName
: CFSTR("Localizable"), CFSTR("strings"), NULL
/*subDirName*/, oneLocalization
));
315 CFPropertyListRef stringTable
;
317 CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(clientBundle
), locURL
, &tableData
, NULL
, NULL
, &errCode
);
321 CFRelease(tableData
);
325 stringTable
= CFPropertyListCreateFromXMLData(CFGetAllocator(clientBundle
), tableData
, kCFPropertyListImmutable
, &errStr
);
326 if (errStr
!= NULL
) {
330 CFRelease(tableData
);
332 CFStringRef value
= static_cast<CFStringRef
>(CFDictionaryGetValue(static_cast<CFDictionaryRef
>(stringTable
), descriptionKey
));
333 if (value
== NULL
|| CFEqual(value
, CFSTR(""))) {
334 CFRelease(stringTable
);
337 // oneLocalization/value into our dictionary
338 CFDictionarySetValue(localizedDescriptions
, oneLocalization
, value
);
339 CFRelease(stringTable
);
344 // add the description as the default localization into the dictionary
345 CFDictionarySetValue(localizedDescriptions
, CFSTR(""), descriptionKey
);
347 // stuff localization table into rule definition
348 CFDictionarySetValue(rightDefinitionDict
, CFSTR(kAuthorizationRuleParameterDefaultPrompt
), localizedDescriptions
);
352 // serialize cfdictionary with data into rightDefinitionXML
353 CFDataRef rightDefinitionXML
= CFPropertyListCreateXMLData(NULL
, rightDefinitionDict
);
355 server().authorizationdbSet(Required(auth
), rightName
, CFDataGetLength(rightDefinitionXML
), CFDataGetBytePtr(rightDefinitionXML
));
361 // AuthorizationRightRemove
363 OSStatus
AuthorizationRightRemove(AuthorizationRef authRef
, const char *rightName
)
367 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authRef
;
368 server().authorizationdbRemove(Required(auth
), rightName
);