securityd_service_client.c [plain text]
#include "securityd_service.h"
#include "securityd_service_client.h"
#include <xpc/xpc.h>
#include <dispatch/dispatch.h>
#include <syslog.h>
#include <AssertMacros.h>
static xpc_connection_t
_service_get_connection()
{
static dispatch_once_t onceToken;
static xpc_connection_t connection = NULL;
dispatch_once(&onceToken, ^{
connection = xpc_connection_create_mach_service(SECURITYD_SERVICE_NAME, NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
require(connection, done);
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, "securityd_service not available");
}
} else {
char * desc = xpc_copy_description(event);
syslog(LOG_ERR, "securityd_service should never get messages on this connection: %s", desc);
free(desc);
}
});
xpc_connection_resume(connection);
done:
return;
});
return connection;
}
static int
_service_send_msg(service_context_t *context, xpc_object_t message, xpc_object_t * reply_out)
{
int rc = KB_GeneralError;
xpc_object_t reply = NULL;
xpc_connection_t conn = NULL;
require(message, done);
conn = _service_get_connection();
require(conn, done);
if (context) {
xpc_dictionary_set_data(message, SERVICE_XPC_CONTEXT, context, sizeof(service_context_t));
}
reply = xpc_connection_send_message_with_reply_sync(conn, message);
require(reply, done);
require(xpc_get_type(reply) != XPC_TYPE_ERROR, done);
rc = (int)xpc_dictionary_get_int64(reply, SERVICE_XPC_RC);
if (reply_out) {
*reply_out = reply;
reply = NULL;
}
done:
if (reply) xpc_release(reply);
return rc;
}
int
_service_client_send_secret(service_context_t *context, uint64_t request, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
{
int rc = KB_GeneralError;
xpc_object_t message = NULL;
message = xpc_dictionary_create(NULL, NULL, 0);
require_quiet(message, done);
xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, request);
if (secret) {
xpc_dictionary_set_data(message, SERVICE_XPC_SECRET, secret, secret_len);
}
if (new_secret) {
xpc_dictionary_set_data(message, SERVICE_XPC_SECRET_NEW, new_secret, new_secret_len);
}
rc = _service_send_msg(context, message, NULL);
done:
if (message) xpc_release(message);
return rc;
}
int
service_client_kb_create(service_context_t *context, const void * secret, int secret_len)
{
return _service_client_send_secret(context, SERVICE_KB_CREATE, secret, secret_len, NULL, 0);
}
int
service_client_kb_load(service_context_t *context)
{
return _service_client_send_secret(context, SERVICE_KB_LOAD, NULL, 0, NULL, 0);
}
int
service_client_kb_unload(service_context_t *context)
{
return _service_client_send_secret(context, SERVICE_KB_UNLOAD, NULL, 0, NULL, 0);
}
int
service_client_kb_save(service_context_t *context)
{
return _service_client_send_secret(context, SERVICE_KB_SAVE, NULL, 0, NULL, 0);
}
int
service_client_kb_unlock(service_context_t *context, const void * secret, int secret_len)
{
return _service_client_send_secret(context, SERVICE_KB_UNLOCK, secret, secret_len, NULL, 0);
}
int
service_client_kb_lock(service_context_t *context)
{
return _service_client_send_secret(context, SERVICE_KB_LOCK, NULL, 0, NULL, 0);
}
int
service_client_kb_change_secret(service_context_t *context, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
{
return _service_client_send_secret(context, SERVICE_KB_CHANGE_SECRET, secret, secret_len, new_secret, new_secret_len);
}
int
service_client_kb_reset(service_context_t *context, const void * secret, int secret_len)
{
return _service_client_send_secret(context, SERVICE_KB_RESET, secret, secret_len, NULL, 0);
}
int service_client_kb_is_locked(service_context_t *context, bool *locked, bool *no_pin)
{
int rc = KB_GeneralError;
xpc_object_t message = NULL;
xpc_object_t reply = NULL;
if (locked) *locked = false;
if (no_pin) *no_pin = false;
message = xpc_dictionary_create(NULL, NULL, 0);
require_quiet(message, done);
xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_KB_IS_LOCKED);
rc = _service_send_msg(context, message, &reply);
if (rc == KB_Success) {
if (locked) {
*locked = xpc_dictionary_get_bool(reply, SERVICE_XPC_LOCKED);
}
if (no_pin) {
*no_pin = xpc_dictionary_get_bool(reply, SERVICE_XPC_NO_PIN);
}
}
done:
if (message) xpc_release(message);
if (reply) xpc_release(reply);
return rc;
}
int
service_client_stash_set_key(service_context_t *context, const void * key, int key_len)
{
int rc = KB_GeneralError;
xpc_object_t message = NULL;
message = xpc_dictionary_create(NULL, NULL, 0);
require_quiet(message, done);
xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_STASH_SET_KEY);
if (key)
xpc_dictionary_set_data(message, SERVICE_XPC_KEY, key, key_len);
rc = _service_send_msg(context, message, NULL);
done:
if (message) xpc_release(message);
return rc;
}
int
service_client_stash_load_key(service_context_t *context, const void * key, int key_len)
{
int rc = KB_GeneralError;
xpc_object_t message = NULL;
message = xpc_dictionary_create(NULL, NULL, 0);
require_quiet(message, done);
xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_STASH_LOAD_KEY);
if (key)
xpc_dictionary_set_data(message, SERVICE_XPC_KEY, key, key_len);
rc = _service_send_msg(context, message, NULL);
done:
if (message) xpc_release(message);
return rc;
}
int
service_client_stash_get_key(service_context_t *context, void ** key, int * key_len)
{
int rc = KB_GeneralError;
xpc_object_t message = NULL;
xpc_object_t reply = NULL;
require(key, done);
require(key_len, done);
message = xpc_dictionary_create(NULL, NULL, 0);
require_quiet(message, done);
xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_STASH_GET_KEY);
rc = _service_send_msg(context, message, &reply);
if (rc == KB_Success) {
size_t data_len = 0;
const void * data = xpc_dictionary_get_data(reply, SERVICE_XPC_KEY, &data_len);
if (data) {
*key = calloc(1u, data_len);
memcpy(*key, data, data_len);
*key_len = (int)data_len;
}
}
done:
if (message) xpc_release(message);
if (reply) xpc_release(reply);
return rc;
}