X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_authorization/lib/Authorization.cpp diff --git a/libsecurity_authorization/lib/Authorization.cpp b/libsecurity_authorization/lib/Authorization.cpp new file mode 100644 index 00000000..54915313 --- /dev/null +++ b/libsecurity_authorization/lib/Authorization.cpp @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// Authorization.cpp +// +// This file is the unified implementation of the Authorization and AuthSession APIs. +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace SecurityServer; +using namespace MachPlusPlus; + + +// +// Shared cached client object +// +class AuthClient : public SecurityServer::ClientSession { +public: + AuthClient() + : SecurityServer::ClientSession(Allocator::standard(), Allocator::standard()) + { } +}; + +static ModuleNexus server; + + +// +// Create an Authorization +// +OSStatus AuthorizationCreate(const AuthorizationRights *rights, + const AuthorizationEnvironment *environment, + AuthorizationFlags flags, + AuthorizationRef *authorization) +{ + BEGIN_API + AuthorizationBlob result; + server().authCreate(rights, environment, flags, result); + if (authorization) + { + *authorization = + (AuthorizationRef) new(server().returnAllocator) AuthorizationBlob(result); + } + else + { + // If no authorizationRef is desired free the one we just created. + server().authRelease(result, flags); + } + END_API(CSSM) +} + + +// +// Free an authorization reference +// +OSStatus AuthorizationFree(AuthorizationRef authorization, AuthorizationFlags flags) +{ + BEGIN_API + AuthorizationBlob *auth = (AuthorizationBlob *)authorization; + server().authRelease(Required(auth, errAuthorizationInvalidRef), flags); + server().returnAllocator.free(auth); + END_API(CSSM) +} + + +// +// Augment and/or interrogate an authorization +// +OSStatus AuthorizationCopyRights(AuthorizationRef authorization, + const AuthorizationRights *rights, + const AuthorizationEnvironment *environment, + AuthorizationFlags flags, + AuthorizationRights **authorizedRights) +{ + BEGIN_API + AuthorizationBlob *auth = (AuthorizationBlob *)authorization; + server().authCopyRights(Required(auth, errAuthorizationInvalidRef), + rights, environment, flags, authorizedRights); + END_API(CSSM) +} + + +// +// Augment and/or interrogate an authorization asynchronously +// +void AuthorizationCopyRightsAsync(AuthorizationRef authorization, + const AuthorizationRights *rights, + const AuthorizationEnvironment *environment, + AuthorizationFlags flags, + AuthorizationAsyncCallback callbackBlock) +{ + __block AuthorizationRights *blockAuthorizedRights = NULL; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + OSStatus status = AuthorizationCopyRights(authorization, rights, environment, flags, &blockAuthorizedRights); + callbackBlock(status, blockAuthorizedRights); + }); +} + + +// +// Retrieve side-band information from an authorization +// +OSStatus AuthorizationCopyInfo(AuthorizationRef authorization, + AuthorizationString tag, + AuthorizationItemSet **info) +{ + BEGIN_API + AuthorizationBlob *auth = (AuthorizationBlob *)authorization; + server().authCopyInfo(Required(auth, errAuthorizationInvalidRef), + tag, Required(info)); + END_API(CSSM) +} + + +// +// Externalize and internalize authorizations +// +OSStatus AuthorizationMakeExternalForm(AuthorizationRef authorization, + AuthorizationExternalForm *extForm) +{ + BEGIN_API + AuthorizationBlob *auth = (AuthorizationBlob *)authorization; + server().authExternalize(Required(auth, errAuthorizationInvalidRef), *extForm); + END_API(CSSM) +} + +OSStatus AuthorizationCreateFromExternalForm(const AuthorizationExternalForm *extForm, + AuthorizationRef *authorization) +{ + BEGIN_API + AuthorizationBlob result; + server().authInternalize(*extForm, result); + Required(authorization, errAuthorizationInvalidRef) = + (AuthorizationRef) new(server().returnAllocator) AuthorizationBlob(result); + + END_API(CSSM) +} + + +// +// Free an ItemSet structure returned from an API call. This is a local operation. +// Since we allocate returned ItemSets as compact blobs, this is just a simple +// free() call. +// +OSStatus AuthorizationFreeItemSet(AuthorizationItemSet *set) +{ + BEGIN_API + server().returnAllocator.free(set); + return errAuthorizationSuccess; + END_API(CSSM) +} + + +// +// This no longer talks to securityd; it is a kernel function. +// +OSStatus SessionGetInfo(SecuritySessionId requestedSession, + SecuritySessionId *sessionId, + SessionAttributeBits *attributes) +{ + BEGIN_API + CommonCriteria::AuditInfo session; + if (requestedSession == callerSecuritySession) + session.get(); + else + session.get(requestedSession); + if (sessionId) + *sessionId = session.sessionId(); + if (attributes) + *attributes = session.flags(); + END_API(CSSM) +} + + +// +// Create a new session. +// This no longer talks to securityd; it is a kernel function. +// Securityd will pick up the new session when we next talk to it. +// +OSStatus SessionCreate(SessionCreationFlags flags, + SessionAttributeBits attributes) +{ + BEGIN_API + + // we don't support the session creation flags anymore + if (flags) + Syslog::warning("SessionCreate flags=0x%x unsupported (ignored)", flags); + CommonCriteria::AuditInfo session; + session.create(attributes); + + // retrieve the (new) session id and set it into the process environment + session.get(); + char idString[80]; + snprintf(idString, sizeof(idString), "%x", session.sessionId()); + setenv("SECURITYSESSIONID", idString, 1); + + END_API(CSSM) +} + + +// +// Get and set the distinguished uid (optionally) associated with the session. +// +OSStatus SessionSetDistinguishedUser(SecuritySessionId session, uid_t user) +{ + BEGIN_API + CommonCriteria::AuditInfo session; + session.get(); + session.ai_auid = user; + session.set(); + END_API(CSSM) +} + + +OSStatus SessionGetDistinguishedUser(SecuritySessionId session, uid_t *user) +{ + BEGIN_API + CommonCriteria::AuditInfo session; + session.get(); + Required(user) = session.uid(); + END_API(CSSM) +} + +OSStatus _SessionSetUserPreferences(SecuritySessionId session); + +void SessionUserPreferencesChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) +{ + _SessionSetUserPreferences(uintptr_t(observer)); +} + +OSStatus _SessionSetUserPreferences(SecuritySessionId session) +{ + BEGIN_API + CFStringRef appleLanguagesStr = CFSTR("AppleLanguages"); + CFStringRef controlTintStr = CFSTR("AppleAquaColorVariant"); + CFStringRef keyboardUIModeStr = CFSTR("AppleKeyboardUIMode"); + CFStringRef textDirectionStr = CFSTR("AppleTextDirection"); + CFStringRef hitoolboxAppIDStr = CFSTR("com.apple.HIToolbox"); + CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); + + CFRef userPrefsDict(CFDictionaryCreateMutable(NULL, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + CFRef globalPrefsDict(CFDictionaryCreateMutable(NULL, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + + if (!userPrefsDict || !globalPrefsDict) + return errSessionValueNotSet; + + CFRef appleLanguagesArray(static_cast(CFPreferencesCopyAppValue(appleLanguagesStr, kCFPreferencesCurrentApplication))); + if (appleLanguagesArray) + CFDictionarySetValue(globalPrefsDict, appleLanguagesStr, appleLanguagesArray); + + CFRef controlTintNumber(static_cast(CFPreferencesCopyAppValue(controlTintStr, kCFPreferencesCurrentApplication))); + if (controlTintNumber) + CFDictionarySetValue(globalPrefsDict, controlTintStr, controlTintNumber); + + CFRef keyboardUIModeNumber(static_cast(CFPreferencesCopyAppValue(keyboardUIModeStr, kCFPreferencesCurrentApplication))); + if (keyboardUIModeNumber) + CFDictionarySetValue(globalPrefsDict, keyboardUIModeStr, keyboardUIModeNumber); + + CFRef textDirectionNumber(static_cast(CFPreferencesCopyAppValue(textDirectionStr, kCFPreferencesCurrentApplication))); + if (textDirectionNumber) + CFDictionarySetValue(globalPrefsDict, textDirectionStr, textDirectionNumber); + + if (CFDictionaryGetCount(globalPrefsDict) > 0) + CFDictionarySetValue(userPrefsDict, kCFPreferencesAnyApplication, globalPrefsDict); + + CFPreferencesSynchronize(hitoolboxAppIDStr, kCFPreferencesCurrentUser, + kCFPreferencesCurrentHost); + CFRef hitoolboxPrefsDict(static_cast(CFPreferencesCopyMultiple(NULL, hitoolboxAppIDStr, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost))); + if (hitoolboxPrefsDict) { + CFDictionarySetValue(userPrefsDict, hitoolboxAppIDStr, hitoolboxPrefsDict); + CFNotificationCenterPostNotification(center, CFSTR("com.apple.securityagent.InputPrefsChanged"), CFSTR("com.apple.loginwindow"), hitoolboxPrefsDict, true); + } + + CFRef userPrefsData(CFPropertyListCreateXMLData(NULL, userPrefsDict)); + if (!userPrefsData) + return errSessionValueNotSet; + server().setSessionUserPrefs(session, CFDataGetLength(userPrefsData), CFDataGetBytePtr(userPrefsData)); + + END_API(CSSM) +} + +OSStatus SessionSetUserPreferences(SecuritySessionId session) +{ + OSStatus status = _SessionSetUserPreferences(session); + if (noErr == status) { + CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); + // We've succeeded in setting up a static set of prefs, now set up + CFNotificationCenterAddObserver(center, (void*)session, SessionUserPreferencesChanged, CFSTR("com.apple.Carbon.TISNotifySelectedKeyboardInputSourceChanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + CFNotificationCenterAddObserver(center, (void*)session, SessionUserPreferencesChanged, CFSTR("com.apple.Carbon.TISNotifyEnabledKeyboardInputSourcesChanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + } + return status; +} + + +// +// Modify Authorization rules +// + +// +// AuthorizationRightGet +// +OSStatus AuthorizationRightGet(const char *rightName, CFDictionaryRef *rightDefinition) +{ + BEGIN_API; + Required(rightName); + CssmDataContainer definition(server().returnAllocator); + + server().authorizationdbGet(rightName, definition, server().returnAllocator); + // convert rightDefinition to dictionary + + if (rightDefinition) + { + CFRef data(CFDataCreate(NULL, static_cast(definition.data()), definition.length())); + if (!data) + CssmError::throwMe(errAuthorizationInternal); + + CFRef rightDict(static_cast(CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL))); + if (!rightDict + || CFGetTypeID(rightDict) != CFDictionaryGetTypeID()) + CssmError::throwMe(errAuthorizationInternal); + + CFRetain(rightDict); + *rightDefinition = rightDict; + } + + END_API(CSSM); +} + +// +// AuthorizationRightSet +// +OSStatus AuthorizationRightSet(AuthorizationRef authRef, + const char *rightName, CFTypeRef rightDefinition, + CFStringRef descriptionKey, CFBundleRef bundle, CFStringRef tableName) +{ + BEGIN_API; + Required(rightName); + AuthorizationBlob *auth = (AuthorizationBlob *)authRef; + + CFRef rightDefinitionDict; + if (rightDefinition && (CFGetTypeID(rightDefinition) == CFStringGetTypeID())) + { + rightDefinitionDict = CFDictionaryCreateMutable(NULL, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!rightDefinitionDict) + CssmError::throwMe(errAuthorizationInternal); + CFDictionarySetValue(rightDefinitionDict, CFSTR(kAuthorizationRightRule), rightDefinition); + } + else + if (rightDefinition && (CFGetTypeID(rightDefinition) == CFDictionaryGetTypeID())) + { + rightDefinitionDict = CFDictionaryCreateMutableCopy(NULL, 0, static_cast(rightDefinition)); + if (!rightDefinitionDict) + CssmError::throwMe(errAuthorizationInternal); + } + else + CssmError::throwMe(errAuthorizationDenied); + + if (rightDefinitionDict) + CFRelease(rightDefinitionDict); // we just assigned things that were already retained + + if (descriptionKey) + { + CFRef localizedDescriptions(CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + + if (!localizedDescriptions) + CssmError::throwMe(errAuthorizationInternal); + + // assigning to perform a retain on either + CFRef clientBundle; clientBundle = bundle ? bundle : CFBundleGetMainBundle(); + + // looks like a list of CFStrings: English us_en etc. + CFRef localizations(CFBundleCopyBundleLocalizations(clientBundle)); + + if (localizations) + { + // for every CFString in localizations do + CFIndex locIndex, allLocs = CFArrayGetCount(localizations); + for (locIndex = 0; locIndex < allLocs; locIndex++) + { + CFStringRef oneLocalization = static_cast(CFArrayGetValueAtIndex(localizations, locIndex)); + + if (!oneLocalization) + continue; + + // @@@ no way to get "Localized" and "strings" as constants? + CFRef locURL(CFBundleCopyResourceURLForLocalization(clientBundle, tableName ? tableName : CFSTR("Localizable"), CFSTR("strings"), NULL /*subDirName*/, oneLocalization)); + + if (!locURL) + continue; + + CFDataRef tableData = NULL; + SInt32 errCode; + CFStringRef errStr; + CFPropertyListRef stringTable; + + CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(clientBundle), locURL, &tableData, NULL, NULL, &errCode); + + if (errCode) + { + if (NULL != tableData) { + CFRelease(tableData); + } + continue; + } + + stringTable = CFPropertyListCreateFromXMLData(CFGetAllocator(clientBundle), tableData, kCFPropertyListImmutable, &errStr); + if (errStr != NULL) { + CFRelease(errStr); + errStr = NULL; + } + CFRelease(tableData); + + CFStringRef value = static_cast(CFDictionaryGetValue(static_cast(stringTable), descriptionKey)); + if (value == NULL || CFEqual(value, CFSTR(""))) { + CFRelease(stringTable); + continue; + } else { + // oneLocalization/value into our dictionary + CFDictionarySetValue(localizedDescriptions, oneLocalization, value); + CFRelease(stringTable); + } + } + } + + // add the description as the default localization into the dictionary + CFDictionarySetValue(localizedDescriptions, CFSTR(""), descriptionKey); + + // stuff localization table into rule definition + CFDictionarySetValue(rightDefinitionDict, CFSTR(kAuthorizationRuleParameterDefaultPrompt), localizedDescriptions); + + } + + // serialize cfdictionary with data into rightDefinitionXML + CFRef rightDefinitionXML(CFPropertyListCreateXMLData(NULL, rightDefinitionDict)); + + server().authorizationdbSet(Required(auth), rightName, CFDataGetLength(rightDefinitionXML), CFDataGetBytePtr(rightDefinitionXML)); + + END_API(CSSM); +} + +// +// AuthorizationRightRemove +// +OSStatus AuthorizationRightRemove(AuthorizationRef authRef, const char *rightName) +{ + BEGIN_API; + Required(rightName); + AuthorizationBlob *auth = (AuthorizationBlob *)authRef; + server().authorizationdbRemove(Required(auth), rightName); + END_API(CSSM); +} +