X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/c38e3ce98599a410a47dc10253faa4d5830f13b2..427c49bcad63d042b29ada2ac27e3dfc4845c779:/libsecurity_authorization/lib/Authorization.c diff --git a/libsecurity_authorization/lib/Authorization.c b/libsecurity_authorization/lib/Authorization.c new file mode 100644 index 00000000..dde4d1aa --- /dev/null +++ b/libsecurity_authorization/lib/Authorization.c @@ -0,0 +1,719 @@ +/* Copyright (c) 2012 Apple Inc. All rights reserved. */ + +#include "Authorization.h" +#include "authd_private.h" +#include "authutilities.h" +#include "debugging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static dispatch_queue_t +get_authorization_dispatch_queue() +{ + static dispatch_once_t onceToken = 0; + static dispatch_queue_t connection_queue = NULL; + + dispatch_once(&onceToken, ^{ + connection_queue = dispatch_queue_create("authorization-connection-queue", DISPATCH_QUEUE_SERIAL); + }); + + return connection_queue; +} + +static xpc_connection_t +get_authorization_connection() +{ + static xpc_connection_t connection = NULL; + + dispatch_sync(get_authorization_dispatch_queue(), ^{ + if (connection == NULL) { + connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL); + + if (!connection) { + syslog(LOG_ERR, "Authorization, failed to create xpc connection to %s", SECURITY_AUTH_NAME); + connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL); + } + + xpc_connection_set_event_handler(connection, ^(xpc_object_t event) { + if (xpc_get_type(event) == XPC_TYPE_ERROR) { + if (event == XPC_ERROR_CONNECTION_INVALID) { + syslog(LOG_ERR, "Authorization, server not available"); + } + // XPC_ERROR_CONNECTION_INTERRUPTED + // XPC_ERROR_TERMINATION_IMMINENT + } else { + char * desc = xpc_copy_description(event); + syslog(LOG_ERR, "Authorization, we should never get messages on this connection: %s", desc); + free(desc); + } + }); + + xpc_connection_resume(connection); + + // Send + xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_SETUP); + mach_port_t bootstrap = MACH_PORT_NULL; + task_get_bootstrap_port(mach_task_self(), &bootstrap); + xpc_dictionary_set_mach_send(message, AUTH_XPC_BOOTSTRAP, bootstrap); + xpc_object_t reply = xpc_connection_send_message_with_reply_sync(connection, message); + xpc_release_safe(message); + xpc_release_safe(reply); + } + }); + + return connection; +} + +static void +setItemSet(xpc_object_t message, const char * key, const AuthorizationItemSet * itemSet) +{ + xpc_object_t serialized = SerializeItemSet(itemSet); + if (serialized) { + xpc_dictionary_set_value(message, key, serialized); + xpc_release(serialized); + } +} + +OSStatus AuthorizationCreate(const AuthorizationRights *rights, + const AuthorizationEnvironment *environment, + AuthorizationFlags flags, + AuthorizationRef *authorization) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + +// require_action(!(rights == NULL && authorization == NULL), done, status = errAuthorizationInvalidSet); + + // Send + message = xpc_dictionary_create(NULL, NULL, 0); + require_action(message != NULL, done, status = errAuthorizationInternal); + + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE); + setItemSet(message, AUTH_XPC_RIGHTS, rights); + setItemSet(message, AUTH_XPC_ENVIROMENT, environment); + xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags | (authorization ? 0 : kAuthorizationFlagNoData)); + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + // Status + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + + // Out + if (authorization && status == errAuthorizationSuccess) { + size_t len; + const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len); + require_action(data != NULL, done, status = errAuthorizationInternal); + assert(len == sizeof(AuthorizationBlob)); + + AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob)); + require_action(blob != NULL, done, status = errAuthorizationInternal); + *blob = *(AuthorizationBlob*)data; + + *authorization = (AuthorizationRef)blob; + } + +done: + xpc_release_safe(message); + xpc_release_safe(reply); + return status; +} + +OSStatus AuthorizationCreateWithAuditToken(audit_token_t token, + const AuthorizationEnvironment *environment, + AuthorizationFlags flags, + AuthorizationRef *authorization) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + + require_action(authorization != NULL, done, status = errAuthorizationInvalidPointer); + + // Send + message = xpc_dictionary_create(NULL, NULL, 0); + require_action(message != NULL, done, status = errAuthorizationInternal); + + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE_WITH_AUDIT_TOKEN); + xpc_dictionary_set_data(message, AUTH_XPC_DATA, &token, sizeof(token)); + setItemSet(message, AUTH_XPC_ENVIROMENT, environment); + xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags); + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + // Status + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + + // Out + if (status == errAuthorizationSuccess) { + size_t len; + const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len); + require_action(data != NULL, done, status = errAuthorizationInternal); + assert(len == sizeof(AuthorizationBlob)); + + AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob)); + require_action(blob != NULL, done, status = errAuthorizationInternal); + *blob = *(AuthorizationBlob*)data; + + *authorization = (AuthorizationRef)blob; + } + +done: + xpc_release_safe(message); + xpc_release_safe(reply); + return status; +} + +OSStatus AuthorizationFree(AuthorizationRef authorization, AuthorizationFlags flags) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + AuthorizationBlob *blob = NULL; + + require_action(authorization != NULL, done, status = errAuthorizationInvalidRef); + blob = (AuthorizationBlob *)authorization; + + // Send + message = xpc_dictionary_create(NULL, NULL, 0); + require_action(message != NULL, done, status = errAuthorizationInternal); + + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_FREE); + xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob)); + xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags); + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + // Status + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + + // Free + free(blob); + +done: + xpc_release_safe(message); + xpc_release_safe(reply); + return status; +} + +static OSStatus +_AuthorizationCopyRights_send_message(xpc_object_t message, AuthorizationRights **authorizedRights) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t reply = NULL; + + // Send + require_action(message != NULL, done, status = errAuthorizationInternal); + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + // Status + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + + // Out + if (authorizedRights && status == errAuthorizationSuccess) { + xpc_object_t tmpItems = xpc_dictionary_get_value(reply, AUTH_XPC_OUT_ITEMS); + AuthorizationRights * grantedRights = DeserializeItemSet(tmpItems); + require_action(grantedRights != NULL, done, status = errAuthorizationInternal); + + *authorizedRights = grantedRights; + } + +done: + xpc_release_safe(reply); + return status; +} + +static OSStatus +_AuthorizationCopyRights_prepare_message(AuthorizationRef authorization, const AuthorizationRights *rights, const AuthorizationEnvironment *environment, AuthorizationFlags flags, xpc_object_t *message_out) +{ + OSStatus status = errAuthorizationInternal; + AuthorizationBlob *blob = NULL; + xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0); + require_action(message != NULL, done, status = errAuthorizationInternal); + + require_action(authorization != NULL, done, status = errAuthorizationInvalidRef); + blob = (AuthorizationBlob *)authorization; + + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_RIGHTS); + xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob)); + setItemSet(message, AUTH_XPC_RIGHTS, rights); + setItemSet(message, AUTH_XPC_ENVIROMENT, environment); + xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags); + + *message_out = message; + message = NULL; + status = errAuthorizationSuccess; + +done: + xpc_release_safe(message); + return status; +} + +OSStatus AuthorizationCopyRights(AuthorizationRef authorization, + const AuthorizationRights *rights, + const AuthorizationEnvironment *environment, + AuthorizationFlags flags, + AuthorizationRights **authorizedRights) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + + require_noerr(status = _AuthorizationCopyRights_prepare_message(authorization, rights, environment, flags, &message), done); + require_noerr(status = _AuthorizationCopyRights_send_message(message, authorizedRights), done); + +done: + xpc_release_safe(message); + return status; +} + + +void AuthorizationCopyRightsAsync(AuthorizationRef authorization, + const AuthorizationRights *rights, + const AuthorizationEnvironment *environment, + AuthorizationFlags flags, + AuthorizationAsyncCallback callbackBlock) +{ + OSStatus prepare_status = errAuthorizationInternal; + __block xpc_object_t message = NULL; + + prepare_status = _AuthorizationCopyRights_prepare_message(authorization, rights, environment, flags, &message); + if (prepare_status != errAuthorizationSuccess) { + callbackBlock(prepare_status, NULL); + } + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + AuthorizationRights *blockAuthorizedRights = NULL; + OSStatus status = _AuthorizationCopyRights_send_message(message, &blockAuthorizedRights); + callbackBlock(status, blockAuthorizedRights); + xpc_release_safe(message); + }); +} + +OSStatus AuthorizationDismiss() +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + + // Send + message = xpc_dictionary_create(NULL, NULL, 0); + require(message != NULL, done); + + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_DISMISS); + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + // Status + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + +done: + xpc_release_safe(message); + xpc_release_safe(reply); + return status; +} + +OSStatus AuthorizationCopyInfo(AuthorizationRef authorization, + AuthorizationString tag, + AuthorizationItemSet **info) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + AuthorizationBlob *blob = NULL; + + require_action(info != NULL, done, status = errAuthorizationInvalidSet); + require_action(authorization != NULL, done, status = errAuthorizationInvalidRef); + blob = (AuthorizationBlob *)authorization; + + // Send + message = xpc_dictionary_create(NULL, NULL, 0); + require_action(message != NULL, done, status = errAuthorizationInternal); + + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_INFO); + xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob)); + if (tag) { + xpc_dictionary_set_string(message, AUTH_XPC_TAG, tag); + } + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + // Status + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + + // Out + if (info && status == errAuthorizationSuccess) { + xpc_object_t tmpItems = xpc_dictionary_get_value(reply, AUTH_XPC_OUT_ITEMS); + AuthorizationRights * outInfo = DeserializeItemSet(tmpItems); + require_action(outInfo != NULL, done, status = errAuthorizationInternal); + + *info = outInfo; + } + +done: + xpc_release_safe(message); + xpc_release_safe(reply); + return status; +} + +OSStatus AuthorizationMakeExternalForm(AuthorizationRef authorization, + AuthorizationExternalForm *extForm) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + AuthorizationBlob *blob = NULL; + + require_action(extForm != NULL, done, status = errAuthorizationInvalidPointer); + require_action(authorization != NULL, done, status = errAuthorizationInvalidRef); + blob = (AuthorizationBlob *)authorization; + + // Send + message = xpc_dictionary_create(NULL, NULL, 0); + require_action(message != NULL, done, status = errAuthorizationInternal); + + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_MAKE_EXTERNAL_FORM); + xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob)); + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + // Status + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + + // out + if (status == errAuthorizationSuccess) { + size_t len; + const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_EXTERNAL, &len); + require_action(data != NULL, done, status = errAuthorizationInternal); + assert(len == sizeof(AuthorizationExternalForm)); + + *extForm = *(AuthorizationExternalForm*)data; + } + +done: + xpc_release_safe(message); + xpc_release_safe(reply); + return status; +} + +OSStatus AuthorizationCreateFromExternalForm(const AuthorizationExternalForm *extForm, + AuthorizationRef *authorization) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + + require_action(extForm != NULL, done, status = errAuthorizationInvalidPointer); + require_action(authorization != NULL, done, status = errAuthorizationInvalidRef); + + // Send + message = xpc_dictionary_create(NULL, NULL, 0); + require_action(message != NULL, done, status = errAuthorizationInternal); + + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_CREATE_FROM_EXTERNAL_FORM); + xpc_dictionary_set_data(message, AUTH_XPC_EXTERNAL, extForm, sizeof(AuthorizationExternalForm)); + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + // Status + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + + // Out + if (authorization && status == errAuthorizationSuccess) { + size_t len; + const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len); + require_action(data != NULL, done, status = errAuthorizationInternal); + assert(len == sizeof(AuthorizationBlob)); + + AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob)); + require_action(blob != NULL, done, status = errAuthorizationInternal); + *blob = *(AuthorizationBlob*)data; + + *authorization = (AuthorizationRef)blob; + } + +done: + xpc_release_safe(message); + xpc_release_safe(reply); + return status; +} + +OSStatus AuthorizationFreeItemSet(AuthorizationItemSet *set) +{ + FreeItemSet(set); + return errAuthorizationSuccess; +} + +OSStatus AuthorizationEnableSmartCard(AuthorizationRef authRef, Boolean enable) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + AuthorizationBlob *blob = NULL; + + // Send + message = xpc_dictionary_create(NULL, NULL, 0); + require_action(message != NULL, done, status = errAuthorizationInternal); + require_action(authRef != NULL, done, status = errAuthorizationInvalidRef); + blob = (AuthorizationBlob *)authRef; + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_ENABLE_SMARTCARD); + xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob)); + xpc_dictionary_set_bool(message, AUTH_XPC_DATA, enable); + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + +done: + xpc_release_safe(message); + xpc_release_safe(reply); + return status; +} + + +OSStatus AuthorizationRightGet(const char *rightName, + CFDictionaryRef *rightDefinition) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + + require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer); + + // Send + message = xpc_dictionary_create(NULL, NULL, 0); + require_action(message != NULL, done, status = errAuthorizationInternal); + + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_GET); + xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName); + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + // Status + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + + // Out + if (rightDefinition && status == errAuthorizationSuccess) { + xpc_object_t value = xpc_dictionary_get_value(reply, AUTH_XPC_DATA); + require_action(value != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(value) == XPC_TYPE_DICTIONARY, done, status = errAuthorizationInternal); + + CFTypeRef cfdict = _CFXPCCreateCFObjectFromXPCObject(value); + require_action(cfdict != NULL, done, status = errAuthorizationInternal); + + *rightDefinition = cfdict; + } + +done: + xpc_release_safe(message); + xpc_release_safe(reply); + return status; +} + +OSStatus AuthorizationRightSet(AuthorizationRef authRef, + const char *rightName, + CFTypeRef rightDefinition, + CFStringRef descriptionKey, + CFBundleRef bundle, + CFStringRef tableName) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + AuthorizationBlob *blob = NULL; + CFMutableDictionaryRef rightDict = NULL; + CFBundleRef clientBundle = bundle; + + if (bundle) { + CFRetain(bundle); + } + + require_action(rightDefinition != NULL, done, status = errAuthorizationInvalidPointer); + require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer); + require_action(authRef != NULL, done, status = errAuthorizationInvalidRef); + blob = (AuthorizationBlob *)authRef; + + // Send + message = xpc_dictionary_create(NULL, NULL, 0); + require_action(message != NULL, done, status = errAuthorizationInternal); + + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_SET); + xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob)); + xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName); + + // Create rightDict + if (CFGetTypeID(rightDefinition) == CFStringGetTypeID()) { + rightDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + require_action(rightDict != NULL, done, status = errAuthorizationInternal); + + CFDictionarySetValue(rightDict, CFSTR(kAuthorizationRightRule), rightDefinition); + + } else if (CFGetTypeID(rightDefinition) == CFDictionaryGetTypeID()) { + rightDict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, rightDefinition); + require_action(rightDict != NULL, done, status = errAuthorizationInternal); + + } else { + status = errAuthorizationInvalidPointer; + goto done; + } + + // Create locDict + if (descriptionKey) { + CFMutableDictionaryRef locDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + require_action(locDict != NULL, done, status = errAuthorizationInternal); + + if (clientBundle == NULL) { + clientBundle = CFBundleGetMainBundle(); + CFRetain(clientBundle); + } + + if (clientBundle) { + CFArrayRef bundleLocalizations = CFBundleCopyBundleLocalizations(clientBundle); + if (bundleLocalizations) { + // for every CFString in localizations do + CFIndex locIndex, allLocs = CFArrayGetCount(bundleLocalizations); + for (locIndex = 0; locIndex < allLocs; locIndex++) + { + CFStringRef oneLocalization = (CFStringRef)CFArrayGetValueAtIndex(bundleLocalizations, locIndex); + + if (!oneLocalization) + continue; + + // @@@ no way to get "Localized" and "strings" as constants? + CFURLRef locURL = CFBundleCopyResourceURLForLocalization(clientBundle, tableName ? tableName : CFSTR("Localizable"), CFSTR("strings"), NULL /*subDirName*/, oneLocalization); + + if (!locURL) + continue; + + CFDataRef tableData = NULL; + SInt32 errCode; + CFStringRef errStr = NULL; + CFPropertyListRef stringTable = NULL; + + CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(clientBundle), locURL, &tableData, NULL, NULL, &errCode); + CFReleaseSafe(locURL); + if (errCode) + { + CFReleaseSafe(tableData); + continue; + } + + stringTable = CFPropertyListCreateFromXMLData(CFGetAllocator(clientBundle), tableData, kCFPropertyListImmutable, &errStr); + CFReleaseSafe(errStr); + CFReleaseSafe(tableData); + + CFStringRef value = (CFStringRef)CFDictionaryGetValue(stringTable, descriptionKey); + if (value == NULL || CFEqual(value, CFSTR(""))) { + CFReleaseSafe(stringTable); + continue; + } else { + // oneLocalization/value into our dictionary + CFDictionarySetValue(locDict, oneLocalization, value); + CFReleaseSafe(stringTable); + } + } + CFReleaseSafe(bundleLocalizations); + } + } + + // add the description as the default localization into the dictionary + CFDictionarySetValue(locDict, CFSTR(""), descriptionKey); + + // stuff localization table into right definition + CFDictionarySetValue(rightDict, CFSTR(kAuthorizationRuleParameterDefaultPrompt), locDict); + CFReleaseSafe(locDict); + } + + xpc_object_t value = _CFXPCCreateXPCObjectFromCFObject(rightDict); + xpc_dictionary_set_value(message, AUTH_XPC_DATA, value); + xpc_release_safe(value); + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + // Status + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + +done: + CFReleaseSafe(clientBundle); + CFReleaseSafe(rightDict); + xpc_release_safe(message); + xpc_release_safe(reply); + return status; +} + +OSStatus AuthorizationRightRemove(AuthorizationRef authorization, + const char *rightName) +{ + OSStatus status = errAuthorizationInternal; + xpc_object_t message = NULL; + xpc_object_t reply = NULL; + AuthorizationBlob *blob = NULL; + + require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer); + require_action(authorization != NULL, done, status = errAuthorizationInvalidRef); + blob = (AuthorizationBlob *)authorization; + + // Send + message = xpc_dictionary_create(NULL, NULL, 0); + require_action(message != NULL, done, status = errAuthorizationInternal); + + xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_RIGHT_REMOVE); + xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob)); + xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName); + + // Reply + reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message); + require_action(reply != NULL, done, status = errAuthorizationInternal); + require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal); + + // Status + status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS); + +done: + xpc_release_safe(message); + xpc_release_safe(reply); + return status; +}