SecTranslocateClient.cpp [plain text]
#include <string>
#include <dispatch/dispatch.h>
#include <xpc/xpc.h>
#include <unistd.h>
#include <security_utilities/unix++.h>
#include <security_utilities/logging.h>
#include "SecTranslocateClient.hpp"
#include "SecTranslocateShared.hpp"
#include "SecTranslocateInterface.hpp"
namespace Security {
namespace SecTranslocate {
using namespace std;
TranslocatorClient::TranslocatorClient(dispatch_queue_t q):syncQ(q)
{
if(syncQ == NULL)
{
Syslog::critical("SecTranslocate::TranslocatorClient initialized without a queue.");
UnixError::throwMe(EINVAL);
}
uint64_t flags = 0;
uid_t euid = geteuid();
if (euid <= 300)
{
flags |= XPC_CONNECTION_MACH_SERVICE_PRIVILEGED; }
service = xpc_connection_create_mach_service(SECTRANSLOCATE_XPC_SERVICE_NAME,
syncQ,
flags);
if (service == NULL)
{
Syslog::critical("SecTranslocate: TranslocatorClient, failed to create xpc mach service");
UnixError::throwMe(ENOMEM);
}
xpc_connection_set_event_handler(service, ^(xpc_object_t event) {
xpc_type_t type = xpc_get_type(event);
if (type == XPC_TYPE_ERROR)
{
Syslog::error("SecTranslocate, client, xpc error: %s", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
}
else
{
char* description = xpc_copy_description(event);
Syslog::error("SecTranslocate, client, xpc unexpected type: %s", description);
free(description);
}
});
dispatch_retain(syncQ);
xpc_connection_resume(service);
}
TranslocatorClient::~TranslocatorClient()
{
xpc_connection_cancel(service);
dispatch_release(syncQ);
}
string TranslocatorClient::translocatePathForUser(const TranslocationPath &originalPath, const string &destPath)
{
string outPath;
if (!originalPath.shouldTranslocate())
{
return originalPath.getOriginalRealPath(); }
xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
if( msg == NULL)
{
Syslog::error("SecTranslocate: TranslocatorClient, failed to allocate message to send");
UnixError::throwMe(ENOMEM);
}
xpc_dictionary_set_string(msg, kSecTranslocateXPCMessageFunction, kSecTranslocateXPCFuncCreate);
xpc_dictionary_set_string(msg, kSecTranslocateXPCMessageOriginalPath, originalPath.getOriginalRealPath().c_str());
if(!destPath.empty())
{
xpc_dictionary_set_string(msg, kSecTranslocateXPCMessageDestinationPath, destPath.c_str());
}
xpc_object_t reply = xpc_connection_send_message_with_reply_sync(service, msg);
xpc_release(msg);
if(reply == NULL)
{
Syslog::error("SecTranslocate, TranslocatorClient, create, no reply returned");
UnixError::throwMe(ENOMEM);
}
xpc_type_t type = xpc_get_type(reply);
if (type == XPC_TYPE_DICTIONARY)
{
if(int64_t error = xpc_dictionary_get_int64(reply, kSecTranslocateXPCReplyError))
{
Syslog::error("SecTranslocate, TranslocatorClient, create, error received %lld", error);
xpc_release(reply);
UnixError::throwMe((int)error);
}
const char * result = xpc_dictionary_get_string(reply, kSecTranslocateXPCReplySecurePath);
if (result == NULL)
{
Syslog::error("SecTranslocate, TranslocatorClient, create, no result path received");
xpc_release(reply);
UnixError::throwMe(EINVAL);
}
outPath=result;
xpc_release(reply);
}
else
{
const char* errorMsg = NULL;
if (type == XPC_TYPE_ERROR)
{
errorMsg = "SecTranslocate, TranslocatorClient, create, xpc error returned: %s";
}
else
{
errorMsg = "SecTranslocate, TranslocatorClient, create, unexpected type of return object: %s";
}
const char *s = xpc_copy_description(reply);
Syslog::error(errorMsg, s);
free((char*)s);
xpc_release(reply);
UnixError::throwMe(EINVAL);
}
return outPath;
}
void TranslocatorClient::appLaunchCheckin(pid_t pid)
{
xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(msg, kSecTranslocateXPCMessageFunction, kSecTranslocateXPCFuncCheckIn);
xpc_dictionary_set_int64(msg, kSecTranslocateXPCMessagePid, pid);
xpc_connection_send_message(service, msg);
xpc_release(msg);
}
bool TranslocatorClient::destroyTranslocatedPathForUser(const string &translocatedPath)
{
Syslog::error("SecTranslocate, TranslocatorClient, delete operation not allowed");
UnixError::throwMe(EPERM);
}
} }