#include "server.h"
#include "session.h"
#include "acls.h"
#include <mach/mach_error.h>
using namespace MachPlusPlus;
Server::Server(Authority &myAuthority, const char *bootstrapName)
: MachServer(bootstrapName),
mCurrentConnection(false),
mCSPModule(gGuidAppleCSP, mCssm), mCSP(mCSPModule),
mAuthority(myAuthority)
{
add(sleepWatcher);
}
Server::~Server()
{
}
Connection &Server::connection(mach_port_t port)
{
Server &server = active();
StLock<Mutex> _(server.lock);
if (Connection *conn = server.connections[port]) {
active().mCurrentConnection = conn;
conn->beginWork();
return *conn;
}
CssmError::throwMe(CSSM_ERRCODE_INVALID_CONTEXT_HANDLE);
}
Connection &Server::connection(bool tolerant)
{
Connection *conn = active().mCurrentConnection;
assert(conn); if (!tolerant)
conn->checkWork();
return *conn;
}
void Server::requestComplete()
{
if (Connection *conn = active().mCurrentConnection) {
if (conn->endWork())
delete conn;
active().mCurrentConnection = NULL;
}
}
SecurityServerAcl &Server::aclBearer(AclKind kind, CSSM_HANDLE handle)
{
SecurityServerAcl &bearer = findHandle<SecurityServerAcl>(handle);
if (kind != bearer.kind())
CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE);
return bearer;
}
void Server::run()
{
MachServer::run(0x10000,
MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER));
}
boolean_t ucsp_server(mach_msg_header_t *, mach_msg_header_t *);
boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out)
{
return ucsp_server(in, out);
}
void Server::setupConnection(Port replyPort, Port taskPort,
const security_token_t &securityToken, const char *identity)
{
StLock<Mutex> _(lock);
Process * &proc = processes[taskPort];
if (proc == NULL) {
proc = new Process(taskPort, identity, securityToken.val[0], securityToken.val[1]);
notifyIfDead(taskPort);
}
Connection *connection = new Connection(*proc, replyPort);
if (connections[replyPort]) CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); connections[replyPort] = connection;
notifyIfDead(replyPort);
}
void Server::endConnection(Port replyPort)
{
StLock<Mutex> _(lock);
Connection *connection = connections[replyPort];
assert(connection);
connections.erase(replyPort);
connection->terminate();
delete connection;
}
Process *Server::resetConnection()
{
Connection *oldConnection = mCurrentConnection;
Process *oldProcess = &oldConnection->process;
debug("SS", "reset process %p connection %p for session switch",
oldProcess, oldConnection);
Port replyPort = oldConnection->clientPort();
oldConnection->endWork();
oldConnection->abort(true);
delete oldConnection;
oldProcess->kill();
Process * &proc = processes[oldProcess->taskPort()];
proc = new Process(*oldProcess);
delete oldProcess;
Connection *connection = new Connection(*proc, replyPort);
connections[replyPort] = connection;
mCurrentConnection = connection;
connection->beginWork();
return proc;
}
void Server::notifyDeadName(Port port)
{
StLock<Mutex> _(lock);
ConnectionMap::iterator conIt = connections.find(port);
if (conIt != connections.end()) {
Connection *connection = conIt->second;
if (connection->abort())
delete connection;
connections.erase(conIt);
return;
}
ProcessMap::iterator procIt = processes.find(port);
if (procIt != processes.end()) {
Process *process = procIt->second;
if (process->kill())
delete process;
processes.erase(procIt);
return;
}
Session::eliminate(Bootstrap(port));
}
void Server::SleepWatcher::systemWillSleep()
{
debug("SS", "sleep notification received");
Database::lockAllDatabases(true);
}
CssmClient::CSP &Server::getCsp()
{
if (!mCssm->isActive()) {
StLock<Mutex> _(lock);
debug("SS", "CSSM initializing");
mCssm->init();
mCSP->attach();
char guids[Guid::stringRepLength+1];
IFDEBUG(debug("SS", "CSSM ready with CSP %s", mCSP->guid().toString(guids)));
}
return mCSP;
}