#include "Authorization.h"
#include "authd_private.h"
#include "authutilities.h"
#include "debugging.h"
#include <Security/AuthorizationPriv.h>
#include <Security/AuthorizationDB.h>
#include <Security/AuthorizationTags.h>
#include <Security/AuthorizationTagsPriv.h>
#include <xpc/xpc.h>
#include <xpc/private.h>
#include <mach/mach.h>
#include <syslog.h>
#include <AssertMacros.h>
#include <CoreFoundation/CFXPCBridge.h>
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");
}
} 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);
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;
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_ENVIRONMENT, environment);
xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags | (authorization ? 0 : kAuthorizationFlagNoData));
reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
require_action_quiet(reply != NULL, done, status = errAuthorizationInternal);
require_action_quiet(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
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);
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_ENVIRONMENT, environment);
xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
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);
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;
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 = 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);
free(blob);
done:
xpc_release_safe(message);
xpc_release_safe(reply);
return status;
}
static OSStatus
_AuthorizationPreauthorizeCredentials_send_message(xpc_object_t message)
{
OSStatus status = errAuthorizationInternal;
xpc_object_t reply = NULL;
require_action(message != NULL, done, status = errAuthorizationInternal);
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(reply);
return status;
}
static OSStatus
_AuthorizationPreauthorizeCredentials_prepare_message(AuthorizationRef authorization, const AuthorizationItemSet *credentials, 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_PREAUTHORIZE_CREDENTIALS);
xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
setItemSet(message, AUTH_XPC_DATA, credentials);
*message_out = message;
message = NULL;
status = errAuthorizationSuccess;
done:
xpc_release_safe(message);
return status;
}
OSStatus AuthorizationPreauthorizeCredentials(AuthorizationRef authorization, const AuthorizationItemSet *credentials)
{
OSStatus status = errAuthorizationInternal;
xpc_object_t message = NULL;
require_noerr(status = _AuthorizationPreauthorizeCredentials_prepare_message(authorization, credentials, &message), done);
require_noerr(status = _AuthorizationPreauthorizeCredentials_send_message(message), done);
done:
xpc_release_safe(message);
return status;
}
static OSStatus
_AuthorizationCopyRights_send_message(xpc_object_t message, AuthorizationRights **authorizedRights)
{
OSStatus status = errAuthorizationInternal;
xpc_object_t reply = NULL;
require_action(message != NULL, done, status = errAuthorizationInternal);
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);
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_ENVIRONMENT, 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;
message = xpc_dictionary_create(NULL, NULL, 0);
require(message != NULL, done);
xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_DISMISS);
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 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;
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 = 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);
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;
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 = 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);
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);
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 = 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);
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;
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 = 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);
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 = 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);
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;
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);
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;
}
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) {
CFIndex locIndex, allLocs = CFArrayGetCount(bundleLocalizations);
for (locIndex = 0; locIndex < allLocs; locIndex++)
{
CFStringRef oneLocalization = (CFStringRef)CFArrayGetValueAtIndex(bundleLocalizations, locIndex);
if (!oneLocalization)
continue;
CFURLRef locURL = CFBundleCopyResourceURLForLocalization(clientBundle, tableName ? tableName : CFSTR("Localizable"), CFSTR("strings"), NULL , 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 {
CFDictionarySetValue(locDict, oneLocalization, value);
CFReleaseSafe(stringTable);
}
}
CFReleaseSafe(bundleLocalizations);
}
}
CFDictionarySetValue(locDict, CFSTR(""), descriptionKey);
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 = 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:
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;
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 = 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;
}