2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
28 // This file is the unified implementation of the Authorization and AuthSession APIs.
31 #include <Security/Authorization.h>
32 #include <Security/AuthorizationPriv.h>
33 #include <Security/AuthorizationDB.h>
34 #include <Security/AuthorizationTagsPriv.h>
35 #include <Security/AuthSession.h>
36 #include <security_utilities/mach++.h>
37 #include <security_utilities/globalizer.h>
38 #include <security_utilities/alloc.h>
39 #include <security_utilities/cfutilities.h>
40 #include <security_cdsa_utilities/cssmbridge.h>
41 #include <security_cdsa_utilities/AuthorizationWalkers.h>
42 #include <security_utilities/ccaudit.h>
43 #include <securityd_client/ssclient.h>
44 #include <CoreFoundation/CFPreferences.h>
45 #include <Carbon/../Frameworks/HIToolbox.framework/Headers/TextInputSources.h>
47 #include <security_utilities/logging.h>
49 using namespace SecurityServer
;
50 using namespace MachPlusPlus
;
54 // Shared cached client object
56 class AuthClient
: public SecurityServer::ClientSession
{
59 : SecurityServer::ClientSession(Allocator::standard(), Allocator::standard())
63 static ModuleNexus
<AuthClient
> server
;
67 // Create an Authorization
69 OSStatus
AuthorizationCreate(const AuthorizationRights
*rights
,
70 const AuthorizationEnvironment
*environment
,
71 AuthorizationFlags flags
,
72 AuthorizationRef
*authorization
)
75 AuthorizationBlob result
;
76 server().authCreate(rights
, environment
, flags
, result
);
80 (AuthorizationRef
) new(server().returnAllocator
) AuthorizationBlob(result
);
84 // If no authorizationRef is desired free the one we just created.
85 server().authRelease(result
, flags
);
92 // Free an authorization reference
94 OSStatus
AuthorizationFree(AuthorizationRef authorization
, AuthorizationFlags flags
)
97 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authorization
;
98 server().authRelease(Required(auth
, errAuthorizationInvalidRef
), flags
);
99 server().returnAllocator
.free(auth
);
105 // Augment and/or interrogate an authorization
107 OSStatus
AuthorizationCopyRights(AuthorizationRef authorization
,
108 const AuthorizationRights
*rights
,
109 const AuthorizationEnvironment
*environment
,
110 AuthorizationFlags flags
,
111 AuthorizationRights
**authorizedRights
)
114 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authorization
;
115 server().authCopyRights(Required(auth
, errAuthorizationInvalidRef
),
116 rights
, environment
, flags
, authorizedRights
);
122 // Augment and/or interrogate an authorization asynchronously
124 void AuthorizationCopyRightsAsync(AuthorizationRef authorization
,
125 const AuthorizationRights
*rights
,
126 const AuthorizationEnvironment
*environment
,
127 AuthorizationFlags flags
,
128 AuthorizationAsyncCallback callbackBlock
)
130 __block AuthorizationRights
*blockAuthorizedRights
= NULL
;
132 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
133 OSStatus status
= AuthorizationCopyRights(authorization
, rights
, environment
, flags
, &blockAuthorizedRights
);
134 callbackBlock(status
, blockAuthorizedRights
);
140 // Retrieve side-band information from an authorization
142 OSStatus
AuthorizationCopyInfo(AuthorizationRef authorization
,
143 AuthorizationString tag
,
144 AuthorizationItemSet
**info
)
147 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authorization
;
148 server().authCopyInfo(Required(auth
, errAuthorizationInvalidRef
),
149 tag
, Required(info
));
155 // Externalize and internalize authorizations
157 OSStatus
AuthorizationMakeExternalForm(AuthorizationRef authorization
,
158 AuthorizationExternalForm
*extForm
)
161 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authorization
;
162 server().authExternalize(Required(auth
, errAuthorizationInvalidRef
), *extForm
);
166 OSStatus
AuthorizationCreateFromExternalForm(const AuthorizationExternalForm
*extForm
,
167 AuthorizationRef
*authorization
)
170 AuthorizationBlob result
;
171 server().authInternalize(*extForm
, result
);
172 Required(authorization
, errAuthorizationInvalidRef
) =
173 (AuthorizationRef
) new(server().returnAllocator
) AuthorizationBlob(result
);
180 // Free an ItemSet structure returned from an API call. This is a local operation.
181 // Since we allocate returned ItemSets as compact blobs, this is just a simple
184 OSStatus
AuthorizationFreeItemSet(AuthorizationItemSet
*set
)
187 server().returnAllocator
.free(set
);
188 return errAuthorizationSuccess
;
194 // This no longer talks to securityd; it is a kernel function.
196 OSStatus
SessionGetInfo(SecuritySessionId requestedSession
,
197 SecuritySessionId
*sessionId
,
198 SessionAttributeBits
*attributes
)
201 CommonCriteria::AuditInfo session
;
202 if (requestedSession
== callerSecuritySession
)
205 session
.get(requestedSession
);
207 *sessionId
= session
.sessionId();
209 *attributes
= session
.flags();
215 // Create a new session.
216 // This no longer talks to securityd; it is a kernel function.
217 // Securityd will pick up the new session when we next talk to it.
219 OSStatus
SessionCreate(SessionCreationFlags flags
,
220 SessionAttributeBits attributes
)
224 // we don't support the session creation flags anymore
226 Syslog::warning("SessionCreate flags=0x%x unsupported (ignored)", flags
);
227 CommonCriteria::AuditInfo session
;
228 session
.create(attributes
);
230 // retrieve the (new) session id and set it into the process environment
233 snprintf(idString
, sizeof(idString
), "%x", session
.sessionId());
234 setenv("SECURITYSESSIONID", idString
, 1);
241 // Get and set the distinguished uid (optionally) associated with the session.
243 OSStatus
SessionSetDistinguishedUser(SecuritySessionId session
, uid_t user
)
246 CommonCriteria::AuditInfo session
;
248 session
.ai_auid
= user
;
254 OSStatus
SessionGetDistinguishedUser(SecuritySessionId session
, uid_t
*user
)
257 CommonCriteria::AuditInfo session
;
259 Required(user
) = session
.uid();
263 OSStatus
_SessionSetUserPreferences(SecuritySessionId session
);
265 void SessionUserPreferencesChanged(CFNotificationCenterRef center
, void *observer
, CFStringRef name
, const void *object
, CFDictionaryRef userInfo
)
267 _SessionSetUserPreferences(uintptr_t(observer
));
270 OSStatus
_SessionSetUserPreferences(SecuritySessionId session
)
273 CFStringRef appleLanguagesStr
= CFSTR("AppleLanguages");
274 CFStringRef controlTintStr
= CFSTR("AppleAquaColorVariant");
275 CFStringRef keyboardUIModeStr
= CFSTR("AppleKeyboardUIMode");
276 CFStringRef textDirectionStr
= CFSTR("AppleTextDirection");
277 CFStringRef hitoolboxAppIDStr
= CFSTR("com.apple.HIToolbox");
278 CFNotificationCenterRef center
= CFNotificationCenterGetDistributedCenter();
280 CFRef
<CFMutableDictionaryRef
> userPrefsDict(CFDictionaryCreateMutable(NULL
, 10, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
));
281 CFRef
<CFMutableDictionaryRef
> globalPrefsDict(CFDictionaryCreateMutable(NULL
, 10, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
));
283 if (!userPrefsDict
|| !globalPrefsDict
)
284 return errSessionValueNotSet
;
286 CFRef
<CFArrayRef
> appleLanguagesArray(static_cast<CFArrayRef
>(CFPreferencesCopyAppValue(appleLanguagesStr
, kCFPreferencesCurrentApplication
)));
287 if (appleLanguagesArray
)
288 CFDictionarySetValue(globalPrefsDict
, appleLanguagesStr
, appleLanguagesArray
);
290 CFRef
<CFNumberRef
> controlTintNumber(static_cast<CFNumberRef
>(CFPreferencesCopyAppValue(controlTintStr
, kCFPreferencesCurrentApplication
)));
291 if (controlTintNumber
)
292 CFDictionarySetValue(globalPrefsDict
, controlTintStr
, controlTintNumber
);
294 CFRef
<CFNumberRef
> keyboardUIModeNumber(static_cast<CFNumberRef
>(CFPreferencesCopyAppValue(keyboardUIModeStr
, kCFPreferencesCurrentApplication
)));
295 if (keyboardUIModeNumber
)
296 CFDictionarySetValue(globalPrefsDict
, keyboardUIModeStr
, keyboardUIModeNumber
);
298 CFRef
<CFNumberRef
> textDirectionNumber(static_cast<CFNumberRef
>(CFPreferencesCopyAppValue(textDirectionStr
, kCFPreferencesCurrentApplication
)));
299 if (textDirectionNumber
)
300 CFDictionarySetValue(globalPrefsDict
, textDirectionStr
, textDirectionNumber
);
302 if (CFDictionaryGetCount(globalPrefsDict
) > 0)
303 CFDictionarySetValue(userPrefsDict
, kCFPreferencesAnyApplication
, globalPrefsDict
);
305 CFPreferencesSynchronize(hitoolboxAppIDStr
, kCFPreferencesCurrentUser
,
306 kCFPreferencesCurrentHost
);
307 CFRef
<CFDictionaryRef
> hitoolboxPrefsDict(static_cast<CFDictionaryRef
>(CFPreferencesCopyMultiple(NULL
, hitoolboxAppIDStr
, kCFPreferencesCurrentUser
, kCFPreferencesCurrentHost
)));
308 if (hitoolboxPrefsDict
) {
309 CFDictionarySetValue(userPrefsDict
, hitoolboxAppIDStr
, hitoolboxPrefsDict
);
310 CFNotificationCenterPostNotification(center
, CFSTR("com.apple.securityagent.InputPrefsChanged"), CFSTR("com.apple.loginwindow"), hitoolboxPrefsDict
, true);
313 CFRef
<CFDataRef
> userPrefsData(CFPropertyListCreateXMLData(NULL
, userPrefsDict
));
315 return errSessionValueNotSet
;
316 server().setSessionUserPrefs(session
, CFDataGetLength(userPrefsData
), CFDataGetBytePtr(userPrefsData
));
321 OSStatus
SessionSetUserPreferences(SecuritySessionId session
)
323 OSStatus status
= _SessionSetUserPreferences(session
);
324 if (noErr
== status
) {
325 CFNotificationCenterRef center
= CFNotificationCenterGetDistributedCenter();
326 // We've succeeded in setting up a static set of prefs, now set up
327 CFNotificationCenterAddObserver(center
, (void*)session
, SessionUserPreferencesChanged
, CFSTR("com.apple.Carbon.TISNotifySelectedKeyboardInputSourceChanged"), NULL
, CFNotificationSuspensionBehaviorDeliverImmediately
);
328 CFNotificationCenterAddObserver(center
, (void*)session
, SessionUserPreferencesChanged
, CFSTR("com.apple.Carbon.TISNotifyEnabledKeyboardInputSourcesChanged"), NULL
, CFNotificationSuspensionBehaviorDeliverImmediately
);
335 // Modify Authorization rules
339 // AuthorizationRightGet
341 OSStatus
AuthorizationRightGet(const char *rightName
, CFDictionaryRef
*rightDefinition
)
345 CssmDataContainer
definition(server().returnAllocator
);
347 server().authorizationdbGet(rightName
, definition
, server().returnAllocator
);
348 // convert rightDefinition to dictionary
352 CFRef
<CFDataRef
> data(CFDataCreate(NULL
, static_cast<UInt8
*>(definition
.data()), definition
.length()));
354 CssmError::throwMe(errAuthorizationInternal
);
356 CFRef
<CFDictionaryRef
> rightDict(static_cast<CFDictionaryRef
>(CFPropertyListCreateFromXMLData(NULL
, data
, kCFPropertyListImmutable
, NULL
)));
358 || CFGetTypeID(rightDict
) != CFDictionaryGetTypeID())
359 CssmError::throwMe(errAuthorizationInternal
);
362 *rightDefinition
= rightDict
;
369 // AuthorizationRightSet
371 OSStatus
AuthorizationRightSet(AuthorizationRef authRef
,
372 const char *rightName
, CFTypeRef rightDefinition
,
373 CFStringRef descriptionKey
, CFBundleRef bundle
, CFStringRef tableName
)
377 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authRef
;
379 CFRef
<CFMutableDictionaryRef
> rightDefinitionDict
;
380 if (rightDefinition
&& (CFGetTypeID(rightDefinition
) == CFStringGetTypeID()))
382 rightDefinitionDict
= CFDictionaryCreateMutable(NULL
, 10, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
383 if (!rightDefinitionDict
)
384 CssmError::throwMe(errAuthorizationInternal
);
385 CFDictionarySetValue(rightDefinitionDict
, CFSTR(kAuthorizationRightRule
), rightDefinition
);
388 if (rightDefinition
&& (CFGetTypeID(rightDefinition
) == CFDictionaryGetTypeID()))
390 rightDefinitionDict
= CFDictionaryCreateMutableCopy(NULL
, 0, static_cast<CFDictionaryRef
>(rightDefinition
));
391 if (!rightDefinitionDict
)
392 CssmError::throwMe(errAuthorizationInternal
);
395 CssmError::throwMe(errAuthorizationDenied
);
397 if (rightDefinitionDict
)
398 CFRelease(rightDefinitionDict
); // we just assigned things that were already retained
402 CFRef
<CFMutableDictionaryRef
> localizedDescriptions(CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
));
404 if (!localizedDescriptions
)
405 CssmError::throwMe(errAuthorizationInternal
);
407 // assigning to perform a retain on either
408 CFRef
<CFBundleRef
> clientBundle
; clientBundle
= bundle
? bundle
: CFBundleGetMainBundle();
410 // looks like a list of CFStrings: English us_en etc.
411 CFRef
<CFArrayRef
> localizations(CFBundleCopyBundleLocalizations(clientBundle
));
415 // for every CFString in localizations do
416 CFIndex locIndex
, allLocs
= CFArrayGetCount(localizations
);
417 for (locIndex
= 0; locIndex
< allLocs
; locIndex
++)
419 CFStringRef oneLocalization
= static_cast<CFStringRef
>(CFArrayGetValueAtIndex(localizations
, locIndex
));
421 if (!oneLocalization
)
424 // @@@ no way to get "Localized" and "strings" as constants?
425 CFRef
<CFURLRef
> locURL(CFBundleCopyResourceURLForLocalization(clientBundle
, tableName
? tableName
: CFSTR("Localizable"), CFSTR("strings"), NULL
/*subDirName*/, oneLocalization
));
430 CFDataRef tableData
= NULL
;
433 CFPropertyListRef stringTable
;
435 CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(clientBundle
), locURL
, &tableData
, NULL
, NULL
, &errCode
);
439 if (NULL
!= tableData
) {
440 CFRelease(tableData
);
445 stringTable
= CFPropertyListCreateFromXMLData(CFGetAllocator(clientBundle
), tableData
, kCFPropertyListImmutable
, &errStr
);
446 if (errStr
!= NULL
) {
450 CFRelease(tableData
);
452 CFStringRef value
= static_cast<CFStringRef
>(CFDictionaryGetValue(static_cast<CFDictionaryRef
>(stringTable
), descriptionKey
));
453 if (value
== NULL
|| CFEqual(value
, CFSTR(""))) {
454 CFRelease(stringTable
);
457 // oneLocalization/value into our dictionary
458 CFDictionarySetValue(localizedDescriptions
, oneLocalization
, value
);
459 CFRelease(stringTable
);
464 // add the description as the default localization into the dictionary
465 CFDictionarySetValue(localizedDescriptions
, CFSTR(""), descriptionKey
);
467 // stuff localization table into rule definition
468 CFDictionarySetValue(rightDefinitionDict
, CFSTR(kAuthorizationRuleParameterDefaultPrompt
), localizedDescriptions
);
472 // serialize cfdictionary with data into rightDefinitionXML
473 CFRef
<CFDataRef
> rightDefinitionXML(CFPropertyListCreateXMLData(NULL
, rightDefinitionDict
));
475 server().authorizationdbSet(Required(auth
), rightName
, CFDataGetLength(rightDefinitionXML
), CFDataGetBytePtr(rightDefinitionXML
));
481 // AuthorizationRightRemove
483 OSStatus
AuthorizationRightRemove(AuthorizationRef authRef
, const char *rightName
)
487 AuthorizationBlob
*auth
= (AuthorizationBlob
*)authRef
;
488 server().authorizationdbRemove(Required(auth
), rightName
);